news 2026/6/25 1:08:03

【面试题】什么是观察者模式?一般用在什么场景?

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
【面试题】什么是观察者模式?一般用在什么场景?

一、什么是观察者模式?

想象一下微信群聊

  • 你发一条消息(发布事件)
  • 群里所有人都收到了通知(观察者被触发)
  • 有些人回复,有些人点赞,有些人潜水(不同的反应)

这就是观察者模式一个对象(被观察者)的状态变化,会通知所有依赖它的对象(观察者)

二、Java代码示例:明星出轨爆料现场 🎬

import java.util.*; // 1. 观察者接口(吃瓜群众) interface GossipObserver { void update(String celebrityName, String scandal); } // 2. 具体观察者:不同反应的人 class ExcitedFan implements GossipObserver { private String name; public ExcitedFan(String name) { this.name = name; } @Override public void update(String celebrityName, String scandal) { System.out.println(name + "兴奋地尖叫:OMG!" + celebrityName + "竟然" + scandal + "!"); System.out.println(" → 立刻打开微博准备吃瓜🍉\n"); } } class CalmJournalist implements GossipObserver { @Override public void update(String celebrityName, String scandal) { System.out.println("记者冷静地记录:"); System.out.println(" 【独家爆料】" + celebrityName + "被曝" + scandal); System.out.println(" → 开始写新闻稿📰\n"); } } class IndifferentPerson implements GossipObserver { @Override public void update(String celebrityName, String scandal) { System.out.println("路人甲瞥了一眼:"); System.out.println(" " + celebrityName + "?不认识。关我屁事🙄"); System.out.println(" → 继续刷抖音\n"); } } // 3. 主题/被观察者接口(八卦中心) interface GossipSubject { void addObserver(GossipObserver observer); // 添加吃瓜群众 void removeObserver(GossipObserver observer); // 移除吃瓜群众 void notifyObservers(); // 发布八卦 } // 4. 具体主题:明星八卦 class CelebrityScandal implements GossipSubject { private String celebrityName; private String scandal; private List<GossipObserver> observers = new ArrayList<>(); public CelebrityScandal(String name) { this.celebrityName = name; } // 明星有新瓜了! public void newScandal(String scandal) { this.scandal = scandal; System.out.println("⚡⚡⚡ 狗仔队拍到:" + celebrityName + " " + scandal + "!"); System.out.println("八卦开始传播...\n"); notifyObservers(); // 通知所有吃瓜群众 } @Override public void addObserver(GossipObserver observer) { observers.add(observer); System.out.println("👥 " + observer.getClass().getSimpleName() + " 加入了吃瓜群"); } @Override public void removeObserver(GossipObserver observer) { observers.remove(observer); System.out.println("🚶 " + observer.getClass().getSimpleName() + " 退群了"); } @Override public void notifyObservers() { for (GossipObserver observer : observers) { observer.update(celebrityName, scandal); } } } // 5. 测试:娱乐圈大戏上演 public class ObserverPatternDemo { public static void main(String[] args) { System.out.println("========== 娱乐圈观察者模式演示 ==========\n"); // 创建八卦中心(被观察者) CelebrityScandal wang = new CelebrityScandal("王某"); // 创建不同的吃瓜群众(观察者) GossipObserver fan1 = new ExcitedFan("狂热粉丝小张"); GossipObserver fan2 = new ExcitedFan("吃瓜少女小李"); GossipObserver journalist = new CalmJournalist(); GossipObserver路人 = new IndifferentPerson(); // 群众陆续加入吃瓜群 wang.addObserver(fan1); wang.addObserver(fan2); wang.addObserver(journalist); wang.addObserver(路人); System.out.println("\n------- 第一波爆料 -------"); // 第一波爆料 wang.newScandal("深夜与神秘女子同回酒店"); System.out.println("\n------- 粉丝退群后第二波爆料 -------"); // 小张退群了 wang.removeObserver(fan1); // 第二波爆料 wang.newScandal("被拍到在超市偷吃试吃品"); } }

运行结果:

========== 娱乐圈观察者模式演示 ========== 👥 ExcitedFan 加入了吃瓜群 👥 ExcitedFan 加入了吃瓜群 👥 CalmJournalist 加入了吃瓜群 👥 IndifferentPerson 加入了吃瓜群 ------- 第一波爆料 ------- ⚡⚡⚡ 狗仔队拍到:王某 深夜与神秘女子同回酒店! 八卦开始传播... 狂热粉丝小张兴奋地尖叫:OMG!王某竟然深夜与神秘女子同回酒店! → 立刻打开微博准备吃瓜🍉 吃瓜少女小李兴奋地尖叫:OMG!王某竟然深夜与神秘女子同回酒店! → 立刻打开微博准备吃瓜🍉 记者冷静地记录: 【独家爆料】王某被曝深夜与神秘女子同回酒店 → 开始写新闻稿📰 路人甲瞥了一眼: 王某?不认识。关我屁事🙄 → 继续刷抖音 ------- 粉丝退群后第二波爆料 ------- 🚶 ExcitedFan 退群了 ⚡⚡⚡ 狗仔队拍到:王某 被拍到在超市偷吃试吃品! 八卦开始传播... 吃瓜少女小李兴奋地尖叫:OMG!王某竟然被拍到在超市偷吃试吃品! → 立刻打开微博准备吃瓜🍉 记者冷静地记录: 【独家爆料】王某被曝被拍到在超市偷吃试吃品 → 开始写新闻稿📰 路人甲瞥了一眼: 王某?不认识。关我屁事🙄 → 继续刷抖音

三、观察者模式的四要素

// 1️⃣ 主题 (Subject) - "八卦中心" // 负责:管理观察者 + 通知变化 interface Subject { void addObserver(Observer o); void removeObserver(Observer o); void notifyObservers(); } // 2️⃣ 观察者 (Observer) - "吃瓜群众" // 负责:定义反应方式 interface Observer { void update(Object data); } // 3️⃣ 具体主题 (ConcreteSubject) - "具体明星" // 负责:状态变化时触发通知 class ConcreteSubject implements Subject { private List<Observer> observers = new ArrayList<>(); private Object state; // 状态 public void setState(Object newState) { this.state = newState; notifyObservers(); // 状态改变,通知所有人! } } // 4️⃣ 具体观察者 (ConcreteObserver) - "具体粉丝" // 负责:实现具体的反应逻辑 class ConcreteObserver implements Observer { @Override public void update(Object data) { // 对状态变化的反应 } }

四、什么时候用观察者模式?

🎯适用场景(三个字:要通知!)

  1. 事件驱动系统- "有事发生,马上报告!"

    // GUI按钮点击事件 button.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { System.out.println("按钮被点了!"); } });
  2. 消息订阅系统- "我有新消息,订阅者请查收"

    // 新闻订阅 newsPublisher.subscribe(user1); newsPublisher.subscribe(user2); // 新文章发布 → 所有订阅者收到推送
  3. 数据监控系统- "数据变了,快更新显示!"

    // 股票价格监控 stock.addObserver(new StockDisplay()); // 显示板 stock.addObserver(new AlertSystem()); // 警报系统 stock.addObserver(new TraderBot()); // 自动交易机器人 // 股价变动 → 所有观察者立即行动
  4. MVC模式- "模型变了,视图快刷新"

    // Model数据变化 model.setData(newData); // → 自动通知所有关联的View更新界面

📦实际项目中的例子

// 电商订单状态通知系统 class Order { private List<OrderObserver> observers = new ArrayList<>(); private String status; public void setStatus(String newStatus) { this.status = newStatus; notifyObservers(); } public void addObserver(OrderObserver observer) { observers.add(observer); } private void notifyObservers() { for (OrderObserver observer : observers) { observer.onOrderStatusChanged(this, status); } } } // 不同的观察者 class CustomerNotifier implements OrderObserver { public void onOrderStatusChanged(Order order, String status) { sendSMS("尊敬的客户,您的订单状态已更新为:" + status); } } class WarehouseSystem implements OrderObserver { public void onOrderStatusChanged(Order order, String status) { if ("已支付".equals(status)) { prepareGoods(order); // 准备发货 } } } class AccountingSystem implements OrderObserver { public void onOrderStatusChanged(Order order, String status) { if ("已完成".equals(status)) { recordRevenue(order); // 记录收入 } } }

五、观察者模式的变体

1.推模型 vs 拉模型

// 推模型:把数据直接推给观察者(常用) void update(String celebrity, String scandal) { // 直接拿到所有信息 } // 拉模型:观察者自己从主题拉取数据 void update(Subject subject) { String scandal = subject.getScandal(); // 自己获取需要的数据 }

2.Java内置支持(已过时但要知道)

import java.util.Observable; // 主题 import java.util.Observer; // 观察者 // 但注意:Observable是类不是接口,Java 9后已废弃

3.事件总线(Event Bus)- 观察者模式的升级版

// 更灵活的事件处理 eventBus.register(subscriber); // 注册订阅者 eventBus.post(new OrderEvent()); // 发布事件 // 所有对OrderEvent感兴趣的订阅者都会收到

六、观察者模式的优缺点

👍优点

  • 松耦合:主题不知道观察者的具体细节,只知道接口
  • 动态添加:运行时可以随时添加/移除观察者
  • 一对多通知:一个变化可以通知多个对象
  • 符合开闭原则:新增观察者无需修改主题

👎缺点

  • 内存泄漏风险:如果观察者没正确移除,可能无法被垃圾回收
  • 通知顺序不确定:观察者被通知的顺序通常无法保证
  • 性能问题:观察者太多时,通知可能变慢
  • 循环依赖:观察者之间相互观察可能导致死循环

🚨注意事项

// 1. 避免在观察者方法中修改主题(可能导致循环或异常) @Override public void update(Subject subject) { // ❌ 错误做法:可能导致递归调用 subject.setState("新状态"); // ✅ 正确做法:只读取不修改 String state = subject.getState(); } // 2. 考虑异步通知(避免阻塞) class AsyncSubject extends Subject { private ExecutorService executor = Executors.newCachedThreadPool(); @Override protected void notifyObservers() { for (Observer observer : observers) { executor.submit(() -> observer.update(data)); // 异步执行 } } }

七、与其他模式的关系

模式关系
发布-订阅模式观察者模式的升级版,通过消息队列解耦
中介者模式都是处理对象间通信,但中介者是集中式管理
责任链模式都是传递事件,但责任链是链式处理

八、生活中的观察者模式

场景主题观察者触发时机
微信群群主群成员有人发消息
天气预报气象局手机APP/电视台天气数据更新
网红直播主播观众开始直播
GitHub仓库代码仓库Star的用户有新提交
电商打折商品收藏的用户价格变化

九、总结:一句话记住

观察者模式 = "我有情况,马上通知大家"

  • 主题:就是那个"有情况的人"
  • 观察者:就是"等着听消息的人"
  • 核心思想解耦+自动通知

📝使用时机判断表

问自己这些问题:

  1. ✅ 一个对象的状态变化需要通知其他对象吗?
  2. ✅ 被通知的对象数量不确定或可能变化吗?
  3. ✅ 不想让这些对象紧密耦合吗?

如果都是"是" → 用观察者模式!

🎯最佳实践

  1. 优先用接口:主题和观察者都用接口定义
  2. 考虑线程安全:多线程环境下要同步
  3. 避免过度使用:简单的回调可能就够了
  4. 使用现有框架:Spring事件、Guava EventBus等

记住口诀:"状态变,发通知;观察者,自动动;松耦合,真轻松!"🎉

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/6/18 4:22:23

日常渗透测试怎么玩?通杀漏洞挖掘的实现方法看这里

如何在日常渗透中实现通杀漏洞挖掘&#xff1f; 你是不是天天遇到了edu刷屏&#xff1f; 看到了某些漏洞平台&#xff0c;某些人交了一千个公益漏洞&#xff1f; 是不是觉得很牛逼&#xff1f;其实不然&#xff0c;都不难&#xff0c;其实如果我要是想刷这玩意&#xff0c;可…

作者头像 李华
网站建设 2026/6/18 4:22:20

2026年网络安全就业前景怎么样?网络安全工程师多少钱一个月?

前言 网络安全工程师是当今互联网行业中备受瞩目的职业之一。随着网络安全问题的不断增加&#xff0c;对于网络安全专业人才的需求也日益增长。然而&#xff0c;网络安全工程师的薪资水平各地区存在一定的差异。那么&#xff0c;网络安全就业前景如何呢&#xff1f; 一、市场需…

作者头像 李华
网站建设 2026/6/22 12:19:14

Python 的常用开发工具

你想了解Python的常用开发工具&#xff0c;我会按「新手友好度」和「使用场景」分类介绍&#xff0c;帮你快速找到适合自己的工具&#xff0c;不管是入门学习还是实际开发都能用上。 一、新手首选&#xff08;易上手、零配置&#xff09; 这类工具门槛极低&#xff0c;不用复杂…

作者头像 李华
网站建设 2026/6/22 12:19:13

阿德勒《自卑与超越》深度解读:于自卑中寻路,在合作中超越

阿德勒《自卑与超越》深度解读&#xff1a;于自卑中寻路&#xff0c;在合作中超越阿尔弗雷德・阿德勒&#xff0c;作为与弗洛伊德、荣格并称的现代心理学三大奠基人&#xff0c;是个体心理学的创始人、人本主义心理学的先驱。不同于弗洛伊德理论的艰深晦涩&#xff0c;他的经典…

作者头像 李华
网站建设 2026/6/22 12:19:11

基于 YOLOv8 的无人机城市交通多目标检测系统 [目标检测完整源码]

基于 YOLOv8 的无人机城市交通多目标检测系统 [目标检测完整源码] 一、应用背景与技术动机 在智慧城市建设进程中&#xff0c;交通运行状态的实时感知已成为城市治理的重要基础能力。相较于传统地面摄像头&#xff0c;无人机具备机动灵活、视角俯瞰、覆盖范围广等优势&#x…

作者头像 李华