观察者模式(Observer Pattern)
观察者模式是一种行为型设计模式,它定义了对象之间的一对多依赖关系,当一个对象(主题)的状态发生变化时,所有依赖它的对象(观察者)都会自动收到通知并更新。这种模式也被称为 “发布 - 订阅模式”(Publish-Subscribe Pattern),核心是 “解耦主题与观察者,让它们可以独立演化”。
一、定义
官方定义:定义对象间的一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都得到通知并被自动更新。
通俗理解:类比生活中的 “订阅报纸”—— 报社(主题)会向所有订阅者(观察者)推送新报纸,订阅者无需主动询问,只需等待通知即可。例如,天气应用中,“天气数据” 是主题,“温度显示面板”“湿度显示面板” 是观察者,当天气数据更新时,所有面板自动刷新。
主题(Subject/Observable)具有注册和移除观察者、并通知所有观察者的功能,主题是通过维护一张观察者列表来实现这些操作的。
观察者(Observer)的注册功能需要调用主题的 registerObserver() 方法。

被观察者 (Observable) 通过 订阅(Subscribe) 按顺序发送事件 给观察者 (Observer), 观察者(Observer) 按顺序接收事件 & 作出对应的响应动作。具体如下图:(类似流水线般流动 & 处理。)

二、意图
- 解耦主题与观察者:主题无需知道观察者的具体类型和数量,只需维护一个观察者列表,观察者也无需知道主题的内部实现。
- 自动同步状态:当主题状态变化时,所有观察者自动收到通知并更新,确保状态一致性。
- 支持动态扩展:可随时添加或移除观察者,无需修改主题或其他观察者的代码(符合开闭原则)。
- 分离关注点:主题专注于状态管理和通知,观察者专注于接收通知后的业务处理。
三、结构
观察者模式包含4 个核心角色,各角色协同实现 “状态变化→自动通知→观察者更新” 的流程:
| 角色名称 | 核心职责 |
|---|---|
| 主题(Subject) | 定义管理观察者的接口: - 注册观察者(registerObserver()); - 移除观察者(removeObserver()); - 通知所有观察者(notifyObservers())。 |
| 具体主题(ConcreteSubject) | 实现主题接口,存储自身状态,当状态变化时调用 notifyObservers() 通知所有观察者。 |
| 观察者(Observer) | 定义接收通知的接口(如 update() 方法),当收到主题通知时更新自身。 |
| 具体观察者(ConcreteObserver) | 实现观察者接口,持有具体主题的引用(可选),在 update() 中根据主题状态执行具体业务逻辑。 |
四、优点
- 低耦合:主题与观察者通过接口通信,彼此无需知道对方的具体实现,降低了模块间的依赖。
- 高扩展性:新增观察者只需实现
Observer接口并注册到主题,无需修改现有代码;新增主题也不影响已有观察者。 - 自动同步:主题状态变化时,所有观察者自动更新,避免了手动同步的繁琐和遗漏。
- 灵活性:可动态添加 / 移除观察者,适应业务需求的变化(如动态订阅 / 取消订阅)。
- 符合开闭原则:对扩展开放(可新增主题 / 观察者),对修改关闭(无需修改现有主题 / 观察者代码)。
五、缺点
- 通知顺序不确定:主题通知观察者时,默认按注册顺序执行,但观察者之间可能存在依赖关系,顺序不确定可能导致逻辑错误。
- 性能开销:若观察者数量过多,主题通知所有观察者的过程可能耗时较长,影响系统响应速度。
- 循环依赖风险:若观察者在
update()中修改主题状态,可能触发新一轮通知,形成循环依赖,导致栈溢出。 - 过度通知:主题状态频繁变化时,观察者会被频繁通知,可能导致不必要的计算或 UI 刷新。
六、类图(Mermaid)

以 “天气监测系统” 为例,类图展示观察者模式的结构:
classDiagram
direction TB
class Subject {
<<interface>>
+registerObserver(observer: Observer): void
+removeObserver(observer: Observer): void
+notifyObservers(): void
}
class ConcreteSubject {
-temperature: float
-humidity: float
-observers: List~Observer~
+setMeasurements(temp: float, humidity: float): void
+getTemperature(): float
+getHumidity(): float
+registerObserver(observer: Observer): void
+removeObserver(observer: Observer): void
+notifyObservers(): void
}
class Observer {
<<interface>>
+update(): void
}
class ConcreteObserverA {
-subject: Subject
-currentTemp: float
-currentHumidity: float
+ConcreteObserverA(subject: Subject)
+update(): void
+display(): void
}
class ConcreteObserverB {
-subject: Subject
+ConcreteObserverB(subject: Subject)
+update(): void
+display(): void
}
Subject <|.. ConcreteSubject
Observer <|.. ConcreteObserverA
Observer <|.. ConcreteObserverB
ConcreteSubject o-- Observer : "包含多个"
ConcreteObserverA o-- Subject : "依赖"
ConcreteObserverB o-- Subject : "依赖"
七、时序图(Mermaid)
以下时序图展示 “天气数据更新后通知所有观察者” 的过程:
sequenceDiagram
participant Client
participant WeatherData as 具体主题(天气数据)
participant TempDisplay as 具体观察者A(温度面板)
participant HumidityDisplay as 具体观察者B(湿度面板)
%% 1. 客户端注册观察者
Client->>TempDisplay: 1. 创建温度面板(关联WeatherData)
TempDisplay->>WeatherData: 2. 注册观察者(registerObserver(this))
Client->>HumidityDisplay: 3. 创建湿度面板(关联WeatherData)
HumidityDisplay->>WeatherData: 4. 注册观察者(registerObserver(this))
%% 2. 主题状态更新
Client->>WeatherData: 5. 推送新天气数据(setMeasurements(25℃, 60%))
WeatherData->>WeatherData: 6. 更新内部状态(temperature=25, humidity=60)
WeatherData->>WeatherData: 7. 触发通知(notifyObservers())
%% 3. 通知所有观察者
WeatherData->>TempDisplay: 8. 调用 update()
TempDisplay->>WeatherData: 9. 拉取数据(getTemperature()=25℃)
TempDisplay->>TempDisplay: 10. 更新显示("当前温度:25℃")
TempDisplay->>WeatherData: 11. 响应完成
WeatherData->>HumidityDisplay: 12. 调用 update()
HumidityDisplay->>WeatherData: 13. 拉取数据(getHumidity()=60%)
HumidityDisplay->>HumidityDisplay: 14. 更新显示("当前湿度:60%")
HumidityDisplay->>WeatherData: 15. 响应完成
WeatherData->>Client: 16. 所有观察者更新完成
八、适用环境
当系统满足以下场景时,适合使用观察者模式:
- 一个对象状态变化需联动更新多个其他对象:如电商订单支付成功后,需通知库存系统减库存、通知积分系统加积分、通知物流系统创建物流单。
- 需解耦状态发布者与订阅者:如 GUI 框架中,按钮(发布者)点击事件需通知多个监听器(订阅者),但按钮无需知道监听器的具体逻辑。
- 需动态管理订阅关系:如新闻 APP 中,用户可随时订阅 / 取消订阅某类新闻,系统需动态维护订阅列表。
- 事件驱动系统:如日志系统(日志事件触发多个处理器)、消息队列(消息发布后被多个消费者处理)。
九、模式分析
- 核心逻辑:观察者模式的本质是 “事件驱动 + 动态依赖”—— 主题作为事件源,状态变化时发布事件,观察者订阅事件并响应,依赖关系可动态调整。
- 两种通知方式:
- 推模型:主题主动将变化的数据推送给观察者(如
update(temp, humidity)),观察者被动接收。 - 拉模型:主题仅通知观察者 “状态已变”,观察者主动从主题拉取数据(如
update()中调用getTemperature()),灵活性更高(观察者可按需获取数据)。
- 推模型:主题主动将变化的数据推送给观察者(如
- 与中介者模式的区别:
- 观察者模式:一对多依赖,主题直接通知所有观察者,适用于简单联动场景。
- 中介者模式:多对多依赖,通过中介者转发通知,适用于复杂交互场景(如多个对象相互影响)。
- 线程安全问题:若主题和观察者在不同线程,需考虑同步机制(如加锁),避免通知过程中观察者被移除导致的异常。
十、模式扩展
观察者模式可根据业务需求扩展出多种变体:
- 带优先级的观察者:观察者注册时指定优先级,主题按优先级顺序通知(解决通知顺序问题)。
- 异步通知:主题通过线程池异步通知观察者,避免同步通知导致的性能阻塞(如 Android 的 Handler 机制)。
- 粘性事件:新注册的观察者可立即收到主题最近一次的状态(如 Android 的 Sticky Broadcast)。
- 观察者分组:主题按类型管理观察者组(如 “天气预警组”“日常天气组”),可针对组进行通知。
- 可取消的通知:观察者在
update()中可返回 “是否继续通知后续观察者”,支持中断通知链。 - 结合装饰器模式:动态为观察者添加额外功能(如日志记录、性能统计),不修改原有观察者逻辑。
十一、模式应用
观察者模式是最常用的设计模式之一,广泛应用于框架、库和业务系统:
- 编程语言与框架:
- Java:
java.util.Observable类和java.util.Observer接口(已过时,推荐使用java.beans包或第三方库)。 - C#:
IObservable和IObserver接口,支持泛型通知。 - JavaScript:事件监听(
addEventListener/removeEventListener)本质是观察者模式。 - Spring:
ApplicationEvent和ApplicationListener实现事件驱动(如ContextRefreshedEvent)。
- Java:
- GUI 框架:
- Swing/AWT:按钮
ActionListener、菜单MenuItemListener等事件监听机制。 - Android:
View.OnClickListener、OnTouchListener等视图事件监听。
- Swing/AWT:按钮
- 消息与事件系统:
- 消息队列(MQ):如 RabbitMQ、Kafka 的发布 - 订阅模式(Topic)。
- 前端框架:Vue 的
$on/$emit、React 的useEffect状态监听。
- 业务系统:
- 电商订单:支付成功后通知库存、积分、物流系统。
- 监控系统:指标超阈值时通知告警模块、日志模块、UI 展示模块。
十二、Android 中的应用
Android 框架大量使用观察者模式,以下是典型场景:
视图事件监听: 按钮、列表等视图的事件监听(如
OnClickListener、OnItemClickListener):button.setOnClickListener(new View.OnClickListener() { // 观察者 @Override public void onClick(View v) { // update() 方法 // 处理点击事件 } }); // 按钮(主题)被点击时,自动调用所有注册的 OnClickListener 的 onClick()BroadcastReceiver(广播接收者): 系统或应用发送广播(主题发布事件),注册的
BroadcastReceiver(观察者)接收并处理:// 注册观察者(广播接收者) registerReceiver(new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { // update() // 处理广播事件 } }, new IntentFilter("com.example.MY_ACTION")); // 发送广播(主题通知) sendBroadcast(new Intent("com.example.MY_ACTION"));LiveData 与 ViewModel: Android 架构组件中,
LiveData是主题,Observer是观察者,数据变化时自动通知 UI 更新:// ViewModel 中的 LiveData(主题) private MutableLiveData<String> userName = new MutableLiveData<>(); // Activity/Fragment 中观察(注册观察者) userName.observe(this, new Observer<String>() { @Override public void onChanged(String name) { // update() // 更新UI显示 textView.setText(name); } }); // 更新数据(主题状态变化,自动通知) userName.setValue("新用户名");RxJava/RxAndroid: 基于观察者模式的响应式编程库,
Observable是主题,Observer是观察者,支持复杂的事件流处理:Observable.just("Hello") // 主题 .subscribe(new Observer<String>() { // 观察者 @Override public void onNext(String s) { // update() Log.d("RxJava", s); } // 其他方法(onError, onComplete) });
十三、代码实现(Java 版)
以 “天气监测系统” 为例,实现观察者模式,包含天气数据(主题)和温度 / 湿度显示面板(观察者):
1. 主题接口(Subject)
import java.util.List;
// 主题接口:定义管理观察者的方法
public interface Subject {
// 注册观察者
void registerObserver(Observer observer);
// 移除观察者
void removeObserver(Observer observer);
// 通知所有观察者
void notifyObservers();
}
2. 观察者接口(Observer)
// 观察者接口:定义接收通知的方法
public interface Observer {
// 接收主题通知(拉模型:观察者主动从主题获取数据)
void update();
}
3. 具体主题(WeatherData)
import java.util.ArrayList;
import java.util.List;
// 具体主题:天气数据(存储温度、湿度,状态变化时通知观察者)
public class WeatherData implements Subject {
private List<Observer> observers; // 观察者列表
private float temperature; // 温度
private float humidity; // 湿度
public WeatherData() {
observers = new ArrayList<>();
}
// 更新天气数据(触发通知)
public void setMeasurements(float temperature, float humidity) {
this.temperature = temperature;
this.humidity = humidity;
notifyObservers(); // 数据更新后通知所有观察者
}
// 提供获取数据的方法(供观察者拉取)
public float getTemperature() {
return temperature;
}
public float getHumidity() {
return humidity;
}
@Override
public void registerObserver(Observer observer) {
observers.add(observer);
}
@Override
public void removeObserver(Observer observer) {
observers.remove(observer);
}
@Override
public void notifyObservers() {
// 遍历所有观察者,调用其 update() 方法
for (Observer observer : observers) {
observer.update();
}
}
}
4. 具体观察者 A(温度显示面板)
// 具体观察者:温度显示面板(显示当前温度)
public class TemperatureDisplay implements Observer {
private Subject weatherData; // 持有主题引用(用于拉取数据)
private float currentTemperature;
// 构造器:注册到主题
public TemperatureDisplay(Subject weatherData) {
this.weatherData = weatherData;
weatherData.registerObserver(this); // 注册为观察者
}
@Override
public void update() {
// 从主题拉取最新温度
currentTemperature = ((WeatherData) weatherData).getTemperature();
display(); // 更新后显示
}
// 显示当前温度
public void display() {
System.out.println("温度显示面板:当前温度 = " + currentTemperature + "℃");
}
}
5. 具体观察者 B(湿度显示面板)
// 具体观察者:湿度显示面板(显示当前湿度)
public class HumidityDisplay implements Observer {
private Subject weatherData;
private float currentHumidity;
public HumidityDisplay(Subject weatherData) {
this.weatherData = weatherData;
weatherData.registerObserver(this);
}
@Override
public void update() {
currentHumidity = ((WeatherData) weatherData).getHumidity();
display();
}
public void display() {
System.out.println("湿度显示面板:当前湿度 = " + currentHumidity + "%");
}
}
6. 客户端(Client)
// 客户端:测试天气监测系统
public class WeatherStationClient {
public static void main(String[] args) {
// 1. 创建主题(天气数据)
WeatherData weatherData = new WeatherData();
// 2. 创建观察者(显示面板)并自动注册到主题
TemperatureDisplay tempDisplay = new TemperatureDisplay(weatherData);
HumidityDisplay humidityDisplay = new HumidityDisplay(weatherData);
// 3. 推送新天气数据(触发通知)
System.out.println("=== 第一次更新天气数据 ===");
weatherData.setMeasurements(25.5f, 60.0f);
// 4. 推送第二次数据
System.out.println("\n=== 第二次更新天气数据 ===");
weatherData.setMeasurements(26.8f, 55.0f);
// 5. 移除湿度面板观察者
System.out.println("\n=== 移除湿度显示面板 ===");
weatherData.removeObserver(humidityDisplay);
// 6. 推送第三次数据(仅温度面板更新)
System.out.println("\n=== 第三次更新天气数据 ===");
weatherData.setMeasurements(24.0f, 65.0f);
}
}
7. 运行结果
=== 第一次更新天气数据 ===
温度显示面板:当前温度 = 25.5℃
湿度显示面板:当前湿度 = 60.0%
=== 第二次更新天气数据 ===
温度显示面板:当前温度 = 26.8℃
湿度显示面板:当前湿度 = 55.0%
=== 移除湿度显示面板 ===
=== 第三次更新天气数据 ===
温度显示面板:当前温度 = 24.0℃
十四、总结
观察者模式通过建立 “主题 - 观察者” 的一对多依赖,实现了状态变化的自动同步和模块解耦,其核心价值在于:
- 解耦依赖:主题与观察者通过接口交互,彼此独立演化,降低系统耦合度。
- 动态扩展:支持随时添加 / 移除观察者,适应业务需求变化,符合开闭原则。
- 事件驱动:以事件为核心,简化了 “一个变化引发多个联动” 场景的实现(如订单支付后的多系统联动)。
在实际开发中,观察者模式是实现 “事件驱动架构” 和 “响应式编程” 的基础,被广泛应用于 GUI 框架、消息系统、状态管理等场景。Android 开发者需重点掌握其在事件监听、LiveData、RxJava 等组件中的应用。
需注意避免通知顺序问题和性能瓶颈:对于复杂场景,可结合优先级队列、异步通知等扩展方式优化;对于多对多交互,可考虑引入中介者模式协调。
总之,观察者模式是处理 “状态联动” 问题的最佳实践,是每个开发者必须掌握的核心设计模式之一。