观察者模式是行为型设计模式的一种,其核心思想是定义对象间的一对多依赖关系

📅 2026/7/7 2:42:46 👁️ 阅读次数 📝 编程学习
观察者模式是行为型设计模式的一种,其核心思想是定义对象间的一对多依赖关系

观察者模式是行为型设计模式的一种,其核心思想是定义对象间的一对多依赖关系,当一个对象的状态发生改变时,所有依赖它的对象都得到通知并被自动更新。观察者模式也称为发布-订阅模式、模型-视图模式,实现了对象间的松耦合,提高了系统的可扩展性。

核心特点

主题和观察者之间是松耦合的,主题不需要知道观察者的具体实现细节

支持广播通信,主题状态变化时会自动通知所有注册的观察者

符合开闭原则,新增观察者不需要修改主题代码

可以实现动态的订阅和取消订阅,灵活管理观察者

核心角色

抽象主题(Subject):定义主题接口,提供注册、移除和通知观察者的方法

具体主题(Concrete Subject):实现抽象主题接口,维护观察者列表,状态变化时通知所有注册的观察者

抽象观察者(Observer):定义观察者接口,提供更新方法,在收到主题通知时执行相应操作

具体观察者(Concrete Observer):实现抽象观察者接口,存储与主题状态相关的信息,在收到通知时更新自身状态

二、适用场景

观察者模式通常应用于以下场景:

事件驱动系统:一个对象的状态变化需要通知其他多个对象,并且不知道有多少个对象需要通知

松耦合设计:需要在对象之间建立松耦合的关系,主题和观察者可以独立变化

多级触发场景:需要实现链式触发机制,一个操作触发一系列后续操作

消息通知系统:如消息推送、事件监听、订阅发布系统等

分布式系统:微服务之间的事件通知、状态同步等场景

UI交互:GUI中的组件事件监听,如按钮点击、文本变化等事件的处理

三、UML类图结构

┌─────────────────────────────┐
│ Subject │
├─────────────────────────────┤
│+attach(Observer) │
│+detach(Observer) │
│+notifyObservers() │
└─────────────────────────────┘


┌─────────────────────────────┐
│ ConcreteSubject │
├─────────────────────────────┤
│-observers: List │ │-state: Object │ ├─────────────────────────────┤ │+attach(Observer) │ │+detach(Observer) │ │+notifyObservers() │ │+getState() │ │+setState(state) │ └─────────────────────────────┘ │ ▼ ┌─────────────────────────────┐ │ Observer │ ├─────────────────────────────┤ │+update(subject) │ └─────────────────────────────┘ ▲ ┌───────┴────────────────────┐ │ │ ┌─────────────────────┐ ┌─────────────────────┐ │ConcreteObserverA │ │ConcreteObserverB │ ├─────────────────────┤ ├─────────────────────┤ │+update(subject) │ │+update(subject) │ └─────────────────────┘ └─────────────────────┘

结构说明:具体主题维护观察者列表,提供注册和移除观察者的方法,当主题状态变化时,通知所有注册的观察者。观察者实现更新接口,在收到通知时根据主题状态更新自身。

四、代码实现示例

以天气站为例,天气数据变化时自动通知所有显示设备更新显示。

1. 抽象主题(天气主题)

2. 抽象观察者(天气观察者)

3. 具体主题(天气数据)

4. 具体观察者(显示设备)

5. 客户端使用示例

五、推模式 vs 拉模式

推模式

主题在通知观察者时,将所有需要的信息推送给观察者,不管观察者是否需要。上面的示例就是推模式,主题将温度、湿度、气压三个参数都推送给观察者。

优点:观察者使用方便,不需要主动获取数据

缺点:灵活性差,如果后续新增参数,需要修改所有观察者的更新方法

拉模式

主题在通知观察者时,只传递主题自身的引用,观察者根据需要主动从主题中拉取所需的数据。

优点:灵活性好,观察者可以按需获取数据,新增参数不需要修改观察者接口

缺点:观察者需要了解主题的结构,增加了耦合度

六、优缺点分析

七、典型应用案例

Java事件模型:AWT/Swing中的事件监听机制是观察者模式的典型应用,组件是主题,监听器是观察者

Spring事件机制:Spring中的ApplicationEvent和ApplicationListener实现了观察者模式,用于处理系统事件

消息队列:RabbitMQ、Kafka等消息中间件的发布订阅模式是观察者模式的分布式实现

ZooKeeper节点监听:ZooKeeper的Watcher机制使用观察者模式,节点状态变化时通知所有注册的Watcher

Android广播机制:Android中的BroadcastReceiver是观察者模式的应用,系统事件变化时通知所有注册的接收器

RxJava响应式编程:RxJava中的Observable和Observer是观察者模式的实现,用于处理异步数据流

微信公众号订阅:公众号是主题,订阅用户是观察者,公众号发布新文章时通知所有订阅用户

八、与其他模式的对比

九、注意事项

根据场景选择推模式或拉模式,推模式适合参数固定的场景,拉模式适合参数多变的场景

注意通知顺序,默认情况下观察者接收通知的顺序与注册顺序一致,如果需要特定顺序可以进行排序

避免循环依赖,主题和观察者之间不要形成循环引用,否则可能导致内存泄漏或死循环

不需要接收通知时要及时注销观察者,避免内存泄漏,特别是在Android等有生命周期的系统中

当观察者数量较多或通知操作耗时较长时,可以考虑使用异步通知,避免阻塞主题的正常运行

在多线程环境下使用观察者模式时,要注意线程安全问题,特别是观察者列表的修改和通知操作

避免过度使用观察者模式