每日一学:设计模式之观察者模式
观察者模式Observer Pattern属于行为型设计模式核心定义构建对象间一对多的依赖关系当被观察者发布者 / 主题状态发生变化时所有订阅它的观察者订阅者会自动收到通知并执行更新逻辑。别名也叫发布 - 订阅模式、监听者模式、Event Listener是日常开发最常用、最易理解的设计模式之一。常见的观察者模式应用消息队列、redis发布订阅、spring事件通知一、观察者模式能解决什么问题举例杂志订阅、公众号推送、商城降价提醒、天气预报推送你订阅公众号后博主发布新文章状态变更所有粉丝自动接收推送无需每个人主动刷新查看。如果不使用观察者模式硬编码耦合一个业务变更需要手动调用多个模块的方法扩展性极差新增业务分支必须修改原有核心代码维护混乱对象之间强依赖一处改动引发连锁 bug。观察者模式完美解决解耦核心业务与后续联动逻辑核心类只负责自身业务无需关心有多少下游依赖方。二、核心角色拆解抽象被观察者Subject维护观察者集合提供订阅、取消订阅、批量通知的抽象方法。具体被观察者Concrete Subject持有自身状态状态变更后触发通知方法推送消息给所有观察者。抽象观察者Observer统一更新接口定义update()方法接收被观察者的通知。具体观察者Concrete Observer实现更新接口自定义收到通知后的业务逻辑。客户端组装被观察者与观察者完成订阅绑定。三、手写 Java 完整实现1. 抽象观察者接口public interface Observer { // 接收通知、执行更新 void update(String message); }2. 抽象被观察者public abstract class Subject { // 维护观察者列表 protected ListObserver 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 拉模式推模式示例实现被观察者主动推送完整数据给观察者观察者直接使用耦合低、使用简单。拉模式被观察者只推送变更信号观察者主动拉取被观察者最新数据适合大数据、复杂场景。六、优缺点分析优点符合开闭原则新增观察者无需修改被观察者代码直接新增实现类即可。松耦合设计被观察者与观察者仅通过接口依赖互不干涉内部逻辑。动态订阅运行时可以灵活新增、取消订阅动态调整依赖关系。事件联动解耦一套状态变更自动触发多模块联动代码简洁优雅。缺点通知顺序不可控默认遍历列表顺序推送无法自定义优先级。性能损耗观察者数量过多时循环通知会产生耗时同步阻塞影响性能。循环依赖风险若观察者内部反向修改被观察者状态容易引发死循环。内存泄漏观察者未主动取消订阅会被被观察者强引用导致无法回收。