以下是 观察者模式 (Observer Pattern) 的详细介绍,包含定义、优缺点、应用场景及代码实现:
一、观察者模式概述
-
英文名称:Observer
-
核心目标:定义对象间的一对多依赖关系,当一个对象(被观察者)状态改变时,所有依赖它的对象(观察者)自动收到通知并更新。
-
设计思想:通过解耦被观察者和观察者,实现松耦合的动态事件通知机制。
二、优缺点
优点:
-
解耦性强:被观察者和观察者相互独立,可单独修改。
-
动态订阅:支持运行时动态添加或移除观察者。
-
广播通信:一对多通知机制,简化事件传播。
缺点:
-
性能开销:观察者数量多时,遍历通知可能耗时。
-
循环依赖:不当设计可能导致循环触发更新。
-
更新顺序不可控:观察者接收通知的顺序不确定。
三、应用场景
-
事件驱动系统:如 GUI 按钮点击事件、游戏角色状态变化。
-
数据监控:如股票价格波动通知、传感器数据更新。
-
消息中间件:如 Kafka、RabbitMQ 的发布-订阅模型。
-
配置中心热更新:配置变更后自动同步到多个服务。
四、代码实现与注释
以下通过 气象站数据发布系统 的案例演示观察者模式:
1. 观察者接口(订阅者)
/**
* 观察者接口:定义数据更新方法
*/
public interface Observer {
void update(float temperature, float humidity);
}
2. 被观察者接口(发布者)
/**
* 被观察者接口:定义订阅、取消订阅和通知方法
*/
public interface Subject {
void registerObserver(Observer observer);
void removeObserver(Observer observer);
void notifyObservers();
}
3. 具体被观察者(气象站)
import java.util.ArrayList;
import java.util.List;
/**
* 具体被观察者:气象站(维护观察者列表并通知数据变化)
*/
public class WeatherStation implements Subject {
private final List<Observer> observers = new ArrayList<>();
private float temperature;
private float humidity;
// 注册观察者
@Override
public void registerObserver(Observer observer) {
observers.add(observer);
}
// 移除观察者
@Override
public void removeObserver(Observer observer) {
observers.remove(observer);
}
// 通知所有观察者
@Override
public void notifyObservers() {
for (Observer observer : observers) {
observer.update(temperature, humidity);
}
}
// 气象站数据更新时触发通知
public void setMeasurements(float temperature, float humidity) {
this.temperature = temperature;
this.humidity = humidity;
notifyObservers();
}
}
4. 具体观察者(显示设备)
/**
* 具体观察者:手机显示设备
*/
public class MobileDisplay implements Observer {
@Override
public void update(float temperature, float humidity) {
System.out.println("[手机] 温度: " + temperature + "°C, 湿度: " + humidity + "%");
}
}
/**
* 具体观察者:电视显示设备
*/
public class TVDisplay implements Observer {
@Override
public void update(float temperature, float humidity) {
System.out.println("[电视] 当前气象数据 => 温度: " + temperature + "°C, 湿度: " + humidity + "%");
}
}
5. 客户端调用
public class Client {
public static void main(String[] args) {
// 创建被观察者(气象站)
WeatherStation weatherStation = new WeatherStation();
// 创建观察者(显示设备)
Observer mobileDisplay = new MobileDisplay();
Observer tvDisplay = new TVDisplay();
// 注册观察者
weatherStation.registerObserver(mobileDisplay);
weatherStation.registerObserver(tvDisplay);
// 更新气象数据,自动触发通知
System.out.println("===== 第一次数据更新 =====");
weatherStation.setMeasurements(25.5f, 65.0f);
// 移除一个观察者后再次更新
weatherStation.removeObserver(tvDisplay);
System.out.println("\n===== 第二次数据更新 =====");
weatherStation.setMeasurements(28.0f, 60.0f);
}
}
6. 输出结果
===== 第一次数据更新 =====
[手机] 温度: 25.5°C, 湿度: 65.0%
[电视] 当前气象数据 => 温度: 25.5°C, 湿度: 65.0%
===== 第二次数据更新 =====
[手机] 温度: 28.0°C, 湿度: 60.0%
五、模式结构图
+----------------+ +----------------+
| Subject | <>-----+ | Observer |
+----------------+ +----------------+
| +register() | | +update() |
| +remove() | +----------------+
| +notify() |
+----------------+
^
|
+----------------+
| ConcreteSubject|
+----------------+
| +getState() |
| +setState() |
+----------------+
|
|
+----------------+
| ConcreteObserver|
+----------------+
| +update() |
+----------------+
六、与其他模式的关系
-
发布-订阅模式:观察者模式是发布-订阅的基础,后者通常引入中间代理层(如消息队列)。
-
中介者模式:中介者协调多个对象间通信,观察者模式侧重单向通知。
-
责任链模式:观察者广播通知,责任链按链传递请求。
七、最佳实践
-
Java 内置支持:
java.util.Observable
和java.util.Observer
(但Observable
类已过时,建议自定义实现)。 -
异步通知:使用线程池或消息队列异步处理观察者更新,避免阻塞。
-
防止竞态条件:确保在遍历观察者列表时线程安全(如使用
CopyOnWriteArrayList
)。
八、总结
-
核心价值:解耦事件发布者与订阅者,实现动态、灵活的事件通知机制。
-
适用场景:需要实现事件驱动、数据同步或状态监听功能的系统。
-
关键实现:被观察者接口 + 观察者接口 + 注册/通知机制。
观察者模式在 Java 生态中广泛应用,例如:
-
Swing/AWT:
ActionListener
监听按钮点击事件。 -
Spring 事件机制:
ApplicationEvent
和ApplicationListener
。 -
ReactiveX:RxJava 的
Observable
和Observer
实现响应式编程。
掌握该模式能有效提升系统的可扩展性和模块化程度。