一、模式定义
观察者模式属于行为型设计模式,用于建立对象间的一对多依赖关系。当主题(Subject)状态变化时,所有依赖的观察者(Observer)会自动收到通知并更新。
二、核心角色
- Subject(主题)
- 维护观察者列表,提供添加/删除观察者的方法
- 定义通知观察者的方法
- Observer(观察者接口)
- 定义更新接口,用于接收主题通知
- ConcreteSubject(具体主题)
- 存储具体状态信息
- 状态改变时触发通知
- ConcreteObserver(具体观察者)
- 实现更新逻辑,保持与主题状态同步
三、经典实现(以气象站为例)
四、两种通知模型对比
特性 |
推模型(Push) |
拉模型(Pull) |
数据传递方式 |
主题主动发送完整数据 |
观察者从主题拉取所需数据 |
实现复杂度 |
观察者可能收到不需要的数据 |
观察者按需获取数据,需要维护主题引用 |
耦合度 |
观察者依赖具体数据结构 |
观察者只需知道主题存在 |
性能考量 |
可能传输冗余数据 |
需要多次调用获取方法 |
拉模型改进示例:
五、Java内置支持
六、模式优劣分析
优势:
- 符合开闭原则:新增观察者无需修改主题
- 运行时动态建立对象关系
- 实现抽象耦合,主题无需知道具体观察者
劣势:
- 通知顺序不可控
- 频繁更新可能影响性能
- 循环依赖风险
七、应用场景
- 跨系统事件通知(如订单状态更新)
- GUI事件处理(按钮点击监听)
- 实时数据监控(股票价格变动)
- 游戏中的成就系统解锁
- 分布式配置中心(配置变更通知)
八、高级应用技巧
- 异步观察者:
使用线程池处理通知,避免阻塞主题线程
- 防止失效监听:
使用弱引用(WeakReference)存储观察者,防止内存泄漏 - 保证通知顺序:
使用PriorityQueue实现带优先级的观察者队列 - 跨进程观察者:
结合消息队列(如RabbitMQ、Kafka)实现分布式观察者模式
九、相关模式对比
- 中介者模式 vs 观察者模式
中介者集中处理对象间通信,而观察者建立直接订阅关系 - 发布-订阅模式 vs 观察者模式
发布-订阅通过消息代理解耦,观察者是直接通信
十、最佳实践建议
- 优先使用拉模型,降低耦合度
- 为观察者接口设计合适的更新粒度
- 考虑使用CopyOnWriteArrayList保证线程安全
- 对于复杂场景,建议使用Guava的EventBus或Spring事件机制