观察者模式 (Observer Pattern)
定义对象间的一种一对多的依赖关系
模式定义
观察者模式是一种行为型设计模式,它定义了对象之间的一对多依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都会得到通知并自动更新。观察者模式又被称为发布-订阅模式,是实现对象间一对多依赖关系的常用设计模式。
模式结构
graph TD
A[Subject] --> B[Observer]
A --> C[ConcreteObserver]
A --> D[ConcreteObserver]
实现方式
基础实现
定义主题接口和观察者接口,实现具体主题和具体观察者。
// 观察者接口
public interface Observer {
void update(float temperature, float humidity, float pressure);
}
// 主题接口
interface Subject {
void registerObserver(Observer observer);
void removeObserver(Observer observer);
void notifyObservers();
}
// 具体主题 - 天气数据
class WeatherData implements Subject {
private List observers;
private float temperature;
private float humidity;
private float pressure;
public WeatherData() {
observers = new ArrayList<>();
}
@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, pressure);
}
}
// 当气象数据更新时调用
public void measurementsChanged() {
notifyObservers();
}
public void setMeasurements(float temperature, float humidity, float pressure) {
this.temperature = temperature;
this.humidity = humidity;
this.pressure = pressure;
measurementsChanged();
}
// getters...
public float getTemperature() { return temperature; }
public float getHumidity() { return humidity; }
public float getPressure() { return pressure; }
}
// 具体观察者 - 当前天气显示
class CurrentConditionsDisplay implements Observer {
private float temperature;
private float humidity;
private Subject weatherData;
public CurrentConditionsDisplay(Subject weatherData) {
this.weatherData = weatherData;
weatherData.registerObserver(this);
}
@Override
public void update(float temperature, float humidity, float pressure) {
this.temperature = temperature;
this.humidity = humidity;
display();
}
public void display() {
System.out.println("当前天气状况: " + temperature + "°C, 湿度: " + humidity + "%");
}
}
使用示例
public class ObserverPatternDemo {
public static void main(String[] args) {
WeatherData weatherData = new WeatherData();
CurrentConditionsDisplay currentDisplay =
new CurrentConditionsDisplay(weatherData);
// 模拟气象数据更新
weatherData.setMeasurements(25.0f, 65.0f, 30.4f);
weatherData.setMeasurements(27.0f, 70.0f, 29.2f);
weatherData.setMeasurements(23.0f, 90.0f, 29.8f);
}
}
经典案例
1. Java内置Observer模式
Java早期版本提供了Observable类和Observer接口:
// 被观察者
class NewsAgency extends Observable {
private String news;
public void setNews(String news) {
this.news = news;
setChanged(); // 标记状态已改变
notifyObservers(news); // 通知所有观察者
}
}
// 观察者
class NewsChannel implements Observer {
private String news;
@Override
public void update(Observable agency, Object news) {
this.news = (String) news;
System.out.println("新闻频道收到最新消息: " + news);
}
}
// 使用示例
NewsAgency agency = new NewsAgency();
NewsChannel channel1 = new NewsChannel();
NewsChannel channel2 = new NewsChannel();
agency.addObserver(channel1);
agency.addObserver(channel2);
agency.setNews("重大新闻:设计模式系列教程上线!");
2. Swing事件处理机制
Java Swing中的事件处理是观察者模式的典型应用:
JButton button = new JButton("点击我");
// 添加事件监听器(观察者)
button.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
System.out.println("按钮被点击了!");
}
});
// 当按钮被点击时,会通知所有注册的监听器
3. RxJava响应式编程
RxJava是观察者模式在现代Java中的高级应用:
Observable observable = Observable.just("Hello", "World");
Observer observer = new Observer() {
@Override
public void onSubscribe(Disposable d) {
System.out.println("订阅开始");
}
@Override
public void onNext(String s) {
System.out.println("收到数据: " + s);
}
@Override
public void onError(Throwable e) {
System.err.println("发生错误: " + e.getMessage());
}
@Override
public void onComplete() {
System.out.println("数据流结束");
}
};
observable.subscribe(observer);
应用场景
- 事件处理系统:GUI事件监听机制
- 消息订阅系统:RSS订阅、邮件订阅等
- 模型-视图架构:MVC中的模型与视图通信
- 实时数据更新:股票价格、天气预报等
- 社交媒体通知:点赞、评论等社交互动
- 游戏状态更新:玩家状态变化通知
优缺点
优点
- 解耦合:主题和观察者之间松耦合,可以独立变化
- 支持广播通信:主题可以通知所有观察者,无需指定具体接收者
- 符合开闭原则:增加新的观察者无需修改主题代码
- 动态关系:可以在运行时建立和解除观察关系
缺点
- 性能问题:通知所有观察者可能很耗时
- 内存泄漏风险:观察者未正确注销可能导致内存泄漏
- 意外更新:一个观察者的更新可能引起连锁反应
- 调试困难:对象间的依赖关系可能使调试变得复杂