观察者模式基础概念
观察者模式(Observer Pattern)是一种行为型设计模式,其核心思想是定义对象间的一种一对多依赖关系,使得当一个对象状态发生改变时,所有依赖它的对象都会得到通知并自动更新。这种模式也被称为发布 - 订阅模式,其中被观察的对象称为主题(Subject),依赖的对象称为观察者(Observer)。
观察者模式的核心组件
- 主题接口(Subject) - 定义主题的基本操作,如注册、移除观察者,以及通知观察者
- 具体主题(ConcreteSubject) - 实现主题接口,维护观察者列表,状态变化时通知观察者
- 观察者接口(Observer) - 定义观察者的更新方法
- 具体观察者(ConcreteObserver) - 实现观察者接口,处理主题通知的更新
观察者模式的实现
下面通过一个天气站的例子展示观察者模式的实现:
import java.util.ArrayList;
import java.util.List;
// 主题接口
interface Subject {
void registerObserver(Observer observer);
void removeObserver(Observer observer);
void notifyObservers();
}
// 观察者接口
interface Observer {
void update(double temperature, double humidity, double pressure);
}
// 具体主题 - 天气数据
class WeatherData implements Subject {
private List<Observer> observers;
private double temperature;
private double humidity;
private double 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(double temperature, double humidity, double pressure) {
this.temperature = temperature;
this.humidity = humidity;
this.pressure = pressure;
measurementsChanged();
}
}
// 具体观察者 - 温度显示
class TemperatureDisplay implements Observer {
@Override
public void update(double temperature, double humidity, double pressure) {
System.out.printf("Temperature Display: %.1f°C%n", temperature);
}
}
// 具体观察者 - 湿度显示
class HumidityDisplay implements Observer {
@Override
public void update(double temperature, double humidity, double pressure) {
System.out.printf("Humidity Display: %.1f%%%n", humidity);
}
}
// 具体观察者 - 气压显示
class PressureDisplay implements Observer {
@Override
public void update(double temperature, double humidity, double pressure) {
System.out.printf("Pressure Display: %.1f hPa%n", pressure);
}
}
// 客户端代码
public class ObserverPatternClient {
public static void main(String[] args) {
// 创建主题
WeatherData weatherData = new WeatherData();
// 创建观察者
Observer tempDisplay = new TemperatureDisplay();
Observer humidityDisplay = new HumidityDisplay();
Observer pressureDisplay = new PressureDisplay();
// 注册观察者
weatherData.registerObserver(tempDisplay);
weatherData.registerObserver(humidityDisplay);
weatherData.registerObserver(pressureDisplay);
// 更新天气数据,触发通知
System.out.println("First weather update:");
weatherData.setMeasurements(25.5, 65.0, 1013.2);
System.out.println("\nSecond weather update:");
weatherData.setMeasurements(26.8, 60.2, 1014.5);
// 移除一个观察者
weatherData.removeObserver(humidityDisplay);
System.out.println("\nThird weather update (after removing humidity display):");
weatherData.setMeasurements(27.3, 58.7, 1012.9);
}
}
Java 内置的观察者模式支持
Java 提供了内置的观察者模式实现,包括java.util.Observable
类和java.util.Observer
接口。不过,自 Java 9 起,这些类已被标记为过时,推荐使用自定义实现或第三方库(如 Guava)。
以下是使用 Java 内置支持的简化示例:
import java.util.Observable;
import java.util.Observer;
// 具体主题(继承Observable类)
class WeatherData extends Observable {
private double temperature;
private double humidity;
private double pressure;
public void setMeasurements(double temperature, double humidity, double pressure) {
this.temperature = temperature;
this.humidity = humidity;
this.pressure = pressure;
setChanged(); // 标记状态已改变
notifyObservers(); // 通知观察者
}
// 获取数据的方法(供观察者使用)
public double getTemperature() {
return temperature;
}
public double getHumidity() {
return humidity;
}
public double getPressure() {
return pressure;
}
}
// 具体观察者(实现Observer接口)
class CurrentConditionsDisplay implements Observer {
@Override
public void update(Observable o, Object arg) {
if (o instanceof WeatherData) {
WeatherData weatherData = (WeatherData) o;
System.out.printf("Current conditions: %.1f°C, %.1f%% humidity%n",
weatherData.getTemperature(), weatherData.getHumidity());
}
}
}
观察者模式的应用场景
- 事件驱动系统 - 如 GUI 编程中的按钮点击事件
- 消息队列系统 - 发布者发布消息,订阅者接收消息
- 状态监控 - 监控系统状态变化并触发相应操作
- 股票市场 - 股票价格变化时通知投资者
- 多人游戏 - 游戏状态变化时通知所有玩家
观察者模式的优缺点
优点:
- 松耦合 - 主题和观察者之间的依赖关系最小化
- 支持广播通信 - 主题可以同时通知多个观察者
- 符合开闭原则 - 可以在不修改主题的情况下新增观察者
- 动态关联 - 可以在运行时动态注册和移除观察者
- 简化对象交互 - 避免对象之间显式的相互引用
缺点:
- 观察者通知顺序不确定 - 多个观察者的更新顺序可能影响系统行为
- 可能导致性能问题 - 大量观察者可能导致通知耗时增加
- 内存泄漏风险 - 如果观察者没有正确移除,可能导致内存泄漏
- 调试困难 - 观察者和主题之间的依赖关系可能使调试复杂化
使用观察者模式的注意事项
- 考虑通知顺序 - 如果观察者的处理顺序重要,需要设计特定的通知机制
- 避免循环依赖 - 确保主题和观察者之间不会形成循环引用
- 考虑异步通知 - 对于耗时操作,考虑使用异步通知避免阻塞
- 状态管理 - 主题应负责管理自身状态并控制通知时机
- 错误处理 - 观察者的异常处理不应影响其他观察者
- 内存管理 - 确保不再需要的观察者被正确移除
观察者模式是一种非常实用的设计模式,它通过定义对象间的一对多依赖关系,实现了对象间的松耦合通信。在实际开发中,观察者模式常用于事件处理系统、实时数据监控、消息传递等需要状态变化通知的场景。