2026/4/18 14:23:35
网站建设
项目流程
如何管理企业网站,手机分销网站公司,做a 免费网站,郑州做网站哪家好一、什么是观察者模式#xff1f;想象一下微信群聊#xff1a;你发一条消息#xff08;发布事件#xff09;群里所有人都收到了通知#xff08;观察者被触发#xff09;有些人回复#xff0c;有些人点赞#xff0c;有些人潜水#xff08;不同的反应#xff09;这就是…一、什么是观察者模式想象一下微信群聊你发一条消息发布事件群里所有人都收到了通知观察者被触发有些人回复有些人点赞有些人潜水不同的反应这就是观察者模式一个对象被观察者的状态变化会通知所有依赖它的对象观察者。二、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 ListGossipObserver 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 ListObserver 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) { // 对状态变化的反应 } }四、什么时候用观察者模式适用场景三个字要通知事件驱动系统- 有事发生马上报告// GUI按钮点击事件 button.addActionListener(new ActionListener() { Override public void actionPerformed(ActionEvent e) { System.out.println(按钮被点了); } });消息订阅系统- 我有新消息订阅者请查收// 新闻订阅 newsPublisher.subscribe(user1); newsPublisher.subscribe(user2); // 新文章发布 → 所有订阅者收到推送数据监控系统- 数据变了快更新显示// 股票价格监控 stock.addObserver(new StockDisplay()); // 显示板 stock.addObserver(new AlertSystem()); // 警报系统 stock.addObserver(new TraderBot()); // 自动交易机器人 // 股价变动 → 所有观察者立即行动MVC模式- 模型变了视图快刷新// Model数据变化 model.setData(newData); // → 自动通知所有关联的View更新界面实际项目中的例子// 电商订单状态通知系统 class Order { private ListOrderObserver 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的用户有新提交电商打折商品收藏的用户价格变化九、总结一句话记住观察者模式 我有情况马上通知大家主题就是那个有情况的人观察者就是等着听消息的人核心思想解耦自动通知使用时机判断表问自己这些问题✅ 一个对象的状态变化需要通知其他对象吗✅ 被通知的对象数量不确定或可能变化吗✅ 不想让这些对象紧密耦合吗如果都是是 → 用观察者模式最佳实践优先用接口主题和观察者都用接口定义考虑线程安全多线程环境下要同步避免过度使用简单的回调可能就够了使用现有框架Spring事件、Guava EventBus等记住口诀状态变发通知观察者自动动松耦合真轻松