当前位置: 首页 > news >正文

每日一学:设计模式之观察者模式

观察者模式(Observer Pattern)属于行为型设计模式,核心定义:构建对象间一对多的依赖关系,当被观察者(发布者 / 主题)状态发生变化时,所有订阅它的观察者(订阅者)会自动收到通知并执行更新逻辑。

别名也叫:发布 - 订阅模式、监听者模式、Event Listener,是日常开发最常用、最易理解的设计模式之一。

常见的观察者模式应用

消息队列、redis发布订阅、spring事件通知

一、观察者模式能解决什么问题

举例

杂志订阅、公众号推送、商城降价提醒、天气预报推送:你订阅公众号后,博主发布新文章(状态变更),所有粉丝自动接收推送,无需每个人主动刷新查看。

如果不使用观察者模式:

  • 硬编码耦合:一个业务变更,需要手动调用多个模块的方法;
  • 扩展性极差:新增业务分支,必须修改原有核心代码;
  • 维护混乱:对象之间强依赖,一处改动引发连锁 bug。

观察者模式完美解决:解耦核心业务与后续联动逻辑,核心类只负责自身业务,无需关心有多少下游依赖方。

二、核心角色拆解

  1. 抽象被观察者(Subject)维护观察者集合,提供订阅、取消订阅、批量通知的抽象方法。
  2. 具体被观察者(Concrete Subject)持有自身状态,状态变更后,触发通知方法,推送消息给所有观察者。
  3. 抽象观察者(Observer)统一更新接口,定义update()方法,接收被观察者的通知。
  4. 具体观察者(Concrete Observer)实现更新接口,自定义收到通知后的业务逻辑。
  5. 客户端组装被观察者与观察者,完成订阅绑定。

三、手写 Java 完整实现

1. 抽象观察者接口

public interface Observer { // 接收通知、执行更新 void update(String message); }

2. 抽象被观察者

public abstract class Subject { // 维护观察者列表 protected List<Observer> observerList = new ArrayList<>(); // 订阅 public abstract void addObserver(Observer observer); // 取消订阅 public abstract void removeObserver(Observer observer); // 通知所有观察者 public abstract void notifyObservers(String message); }

3. 具体被观察者(消息发布方)

public class MessageSubject extends Subject { @Override public void addObserver(Observer observer) { observerList.add(observer); } @Override public void removeObserver(Observer observer) { observerList.remove(observer); } @Override public void notifyObservers(String message) { // 遍历所有观察者,推送消息 for (Observer observer : observerList) { observer.update(message); } } }

4. 具体观察者(多端接收方)

// 短信通知观察者 public class SmsObserver implements Observer { @Override public void update(String message) { System.out.println("短信接收通知:" + message); } } // 邮件通知观察者 public class EmailObserver implements Observer { @Override public void update(String message) { System.out.println("邮件接收通知:" + message); } } // 站内信观察者 public class WebObserver implements Observer { @Override public void update(String message) { System.out.println("站内信接收通知:" + message); } }

5. 测试

public class ObserverDemo { public static void main(String[] args) { // 1. 创建被观察者 MessageSubject subject = new MessageSubject(); // 2. 创建多个观察者 Observer sms = new SmsObserver(); Observer email = new EmailObserver(); Observer web = new WebObserver(); // 3. 绑定订阅关系 subject.addObserver(sms); subject.addObserver(email); subject.addObserver(web); // 4. 被观察者状态变更,自动推送通知 System.out.println("===商城活动更新==="); subject.notifyObservers("双十一活动正式开启,全场五折!"); // 5. 取消单个订阅 subject.removeObserver(web); System.out.println("\n===价格变更通知==="); subject.notifyObservers("爆款商品限时降价200元"); } }

运行结果

===商城活动更新=== 短信接收通知:双十一活动正式开启,全场五折! 邮件接收通知:双十一活动正式开启,全场五折! 站内信接收通知:双十一活动正式开启,全场五折! ===价格变更通知=== 短信接收通知:爆款商品限时降价200元 邮件接收通知:爆款商品限时降价200元

四、JDK 原生观察者支持(拓展)

Java 内置提供了观察者模式原生实现,无需手动编写集合管理:

  • 被观察者:继承Observable
  • 观察者:实现Observer接口

注意:JDK 原生实现已标记过时,不推荐生产使用,仅作学习参考。

五、推模式 vs 拉模式

  1. 推模式(示例实现)被观察者主动推送完整数据给观察者,观察者直接使用,耦合低、使用简单。
  2. 拉模式被观察者只推送变更信号,观察者主动拉取被观察者最新数据,适合大数据、复杂场景。

六、优缺点分析

优点

  1. 符合开闭原则新增观察者无需修改被观察者代码,直接新增实现类即可。
  2. 松耦合设计被观察者与观察者仅通过接口依赖,互不干涉内部逻辑。
  3. 动态订阅运行时可以灵活新增、取消订阅,动态调整依赖关系。
  4. 事件联动解耦一套状态变更,自动触发多模块联动,代码简洁优雅。

缺点

  1. 通知顺序不可控默认遍历列表顺序推送,无法自定义优先级。
  2. 性能损耗观察者数量过多时,循环通知会产生耗时,同步阻塞影响性能。
  3. 循环依赖风险若观察者内部反向修改被观察者状态,容易引发死循环。
  4. 内存泄漏观察者未主动取消订阅,会被被观察者强引用,导致无法回收。
http://www.jsqmd.com/news/706736/

相关文章:

  • 从虚拟化到容器化:华为云弹性计算架构的演进与实践
  • 重庆二手房历史交易信息2015-2023年
  • R语言机器学习模型保存与部署实战指南
  • 2026就近回收技术解析:西餐厅回收/高价回收/上门回收/专业回收/中餐馆回收/二手货回收/厨房设备回收/奶茶店回收/选择指南 - 优质品牌商家
  • NVIDIA Nemotron 3架构解析:智能体AI与混合Mamba-Transformer MoE设计
  • RNN与LSTM:序列预测模型原理与实战技巧
  • 2026无纺布中药煎药袋标杆名录:水果果框套袋透气袋、汽车配件包装透气袋、热封款无纺布袋、缝纫款无纺布袋、蔬菜框套袋透气袋选择指南 - 优质品牌商家
  • 想给照片换背景底色?2026 年这几款工具+1 个微信小程序的搭配建议
  • RAGFlow · 第 3 章:第一节 RAGFlow 配置参数全景图与实验结论
  • 机器学习概率校准:原理与实践指南
  • Proxmox VE Ceph 超融合集群落地实战
  • 成都地区、H型钢、340X250X9X14、Q235B、包钢、现货批发供应 - 四川盛世钢联营销中心
  • 5分钟快速上手:崩坏星穹铁道游戏自动化脚本终极指南
  • 紧急预警:MCP 1.8+版本中隐藏的跨模态梯度坍塌风险(附3行代码热修复方案)
  • 商业航天与航空安全场景下抗辐射 MCU 选型、应用实践及发展趋势
  • 【紧急更新】VS Code 1.92+已默认启用MCP v2.1协议!你的插件生态是否已通过RFC-8921合规性审计?
  • Superpowers:可视化编排AI智能体,构建协作式应用开发平台
  • PyTorch实现逻辑回归:从原理到实战
  • LaVague:赋予大语言模型GUI操作能力的开源AI智能体框架
  • 10款机器学习运维(MLOps)工具实战指南
  • 智能结对编程工具the-pair:实时代码审查与AI辅助开发实践
  • 构建机器学习作品集:提升数据科学求职竞争力的关键策略
  • 利用Obsidian Local REST API构建可检索的AI对话知识库
  • 时间序列重采样与插值技术详解
  • DaVinci Linux驱动架构与优化实践
  • Docker + WASM边缘计算落地实战:5个被90%团队忽略的关键配置,今天必须改!
  • Jenkins EC2 Plugin实战:动态构建代理的弹性伸缩与成本优化
  • hcia第四次作业
  • 【无标题】彻底吃透Java String:从基础原理到实战优化,一篇全搞定
  • 谷歌SEO如何做图标优化?