news 2026/4/23 18:01:38

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

作者头像

张小明

前端开发工程师

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/4/23 11:34:39

MySQL大事务的Recovery优化

你有没有碰到过mysqld进程启动了很长时间也起不来的情况&#xff1f;这时候我们可以用perf top命令查看一下MySQL进程主要在干什么事情。如果你查看到的信息如下图所示&#xff0c;启动过程中MySQL的主线程(mysqld_main函数开始的线程)绝大多数的时间都花在了回滚事务上。那么很…

作者头像 李华
网站建设 2026/4/23 11:34:52

程序员转型大模型产品经理必看:收藏这份详细学习路线_大模型产品经理学习路线详述

本文为有志成为大模型产品的人提供了完整的学习路线&#xff0c;从基础知识到深化理解再到实战演练&#xff0c;系统性地规划了成长路径。文章详细介绍了所需的技术知识、产品管理理论和实战经验&#xff0c;并提供了丰富的学习资源&#xff0c;帮助读者系统掌握大模型产品经理…

作者头像 李华
网站建设 2026/4/23 13:42:46

环保与水务行业PLC设备远程诊断与维护解决方案

水务行业的泵站、污水处理厂&#xff0c;环保行业的监测站、除污设备等&#xff0c;通常分布广泛、地处偏远。一旦PLC控制系统出现程序故障或参数异常&#xff0c;需要派遣专业工程师长途跋涉现场处理&#xff0c;响应周期长、差旅成本高&#xff0c;且故障期间可能导致工艺中断…

作者头像 李华
网站建设 2026/4/23 12:15:52

智能合约重入攻击防护验证:测试从业者的全面指南

在区块链技术日益普及的今天&#xff0c;智能合约的安全漏洞&#xff0c;尤其是重入攻击&#xff0c;已成为软件测试从业者必须关注的核心风险。重入攻击指恶意合约在未完成当前操作前&#xff0c;反复调用目标合约函数&#xff0c;导致资金或状态被非法窃取&#xff08;例如20…

作者头像 李华
网站建设 2026/4/23 12:24:07

全网最全本科生AI论文平台TOP9:开题报告文献综述测评

全网最全本科生AI论文平台TOP9&#xff1a;开题报告文献综述测评 2026年本科生AI论文平台测评&#xff1a;为何需要这份权威榜单&#xff1f; 随着人工智能技术的快速发展&#xff0c;越来越多的本科生开始借助AI工具辅助论文写作。然而&#xff0c;面对市场上琳琅满目的平台&a…

作者头像 李华