目录
- 1. 什么是观察者模式
- 2. 为什么需要观察者模式
- 3. 观察者模式的结构
- 4. 实现示例
- 5. Java内置的观察者实现
- 6. 最佳实践与注意事项
1. 什么是观察者模式
观察者模式是一种行为型设计模式,它定义了一种一对多的依赖关系,让多个观察者对象同时监听某一个主题对象。当主题对象发生变化时,它的所有观察者都会收到通知并自动更新。
这种模式被广泛应用于事件处理系统中,比如:
- GUI系统中的事件处理
- 消息推送系统
- 订阅发布机制
2. 为什么需要观察者模式
观察者模式主要解决以下问题:
- 解耦合:将观察者和被观察者解耦,使得它们可以独立变化
- 实现一对多关系:一个对象的状态改变可以通知多个订阅者
- 支持广播通信:不需要明确指定接收者,所有订阅者都能收到通知
3. 观察者模式的结构
UML类图
核心角色
- Subject(主题):
- 持有观察者集合
- 提供注册和删除观察者的方法
- 通知所有观察者的方法
- Observer(观察者):
- 定义更新接口
- 收到主题通知时进行更新
- ConcreteSubject(具体主题):
- Subject 的具体实现类
- 存储观察者感兴趣的状态
- 当状态发生改变时通知观察者
- ConcreteObserver(具体观察者):
- Observer 的具体实现类
- 维护一个指向 ConcreteSubject 对象的引用
- 存储感兴趣的状态,这些状态需要和主题的状态保持一致
- 实现 Observer 的更新接口,使自身状态与主题的状态保持一致
4. 实现示例
让我们通过一个具体的例子来理解观察者模式。假设我们要实现一个天气监测系统:
// 观察者接口
public interface WeatherObserver {void update(float temperature, float humidity, float pressure);
}// 主题接口
public interface WeatherSubject {void registerObserver(WeatherObserver observer);void removeObserver(WeatherObserver observer);void notifyObservers();
}// 具体主题:气象站
public class WeatherStation implements WeatherSubject {private List<WeatherObserver> observers;private float temperature;private float humidity;private float pressure;public WeatherStation() {observers = new ArrayList<>();}@Overridepublic void registerObserver(WeatherObserver observer) {observers.add(observer);}@Overridepublic void removeObserver(WeatherObserver observer) {observers.remove(observer);}@Overridepublic void notifyObservers() {for (WeatherObserver observer : observers) {observer.update(temperature, humidity, pressure);}}// 当气象测量值改变时调用此方法public void setMeasurements(float temperature, float humidity, float pressure) {this.temperature = temperature;this.humidity = humidity;this.pressure = pressure;notifyObservers();}
}// 具体观察者:显示当前天气
public class CurrentConditionsDisplay implements WeatherObserver {private float temperature;private float humidity;private float pressure;@Overridepublic void update(float temperature, float humidity, float pressure) {this.temperature = temperature;this.humidity = humidity;this.pressure = pressure;display();}public void display() {System.out.println("当前温度: " + temperature + "°C");System.out.println("当前湿度: " + humidity + "%");System.out.println("当前气压: " + pressure + "hPa");}
}// 使用示例
public class WeatherStationDemo {public static void main(String[] args) {WeatherStation weatherStation = new WeatherStation();CurrentConditionsDisplay display = new CurrentConditionsDisplay();// 注册观察者weatherStation.registerObserver(display);// 更新天气数据weatherStation.setMeasurements(25.2f, 65.0f, 1013.1f);}
}
运行结果:
当前温度: 25.2°C
当前湿度: 65.0%
当前气压: 1013.1hPa
运行结果说明:
- 首先创建了一个
WeatherStation
对象(主题)和一个CurrentConditionsDisplay
对象(观察者) - 通过
registerObserver()
方法将显示器注册为气象站的观察者 - 当调用
setMeasurements()
更新气象数据时:- 气象站内部的数据被更新
- 自动调用
notifyObservers()
通知所有观察者 - 观察者的
update()
方法被调用,接收最新数据 - 显示器随即更新显示最新的气象信息
这个简单的例子展示了观察者模式的核心工作流程:对象状态改变 → 自动通知 → 观察者更新,整个过程中主题和观察者都保持松耦合。
5. Java内置的观察者实现
Java提供了内置的观察者模式支持,通过java.util.Observable
类和java.util.Observer
接口:
import java.util.Observable;
import java.util.Observer;// 继承Observable的气象站
public class JavaWeatherStation extends Observable {private float temperature;private float humidity;private float pressure;public void setMeasurements(float temperature, float humidity, float pressure) {this.temperature = temperature;this.humidity = humidity;this.pressure = pressure;setChanged(); // 标记状态已改变notifyObservers(new float[]{temperature, humidity, pressure});}
}// 实现Observer接口的显示器
public class JavaCurrentConditionsDisplay implements Observer {@Overridepublic void update(Observable observable, Object arg) {if (arg instanceof float[]) {float[] measurements = (float[]) arg;float temperature = measurements[0];float humidity = measurements[1];float pressure = measurements[2];System.out.println("当前温度: " + temperature + "°C");System.out.println("当前湿度: " + humidity + "%");System.out.println("当前气压: " + pressure + "hPa");}}
}
注意:从Java 9开始,Observable
和Observer
已被标记为废弃,建议使用其他替代方案,如Flow API或自定义实现。
6. 最佳实践与注意事项
- 避免循环依赖:
- 确保观察者和主题之间不会形成循环依赖
- 注意在通知观察者时不要触发新的更新循环
- 内存管理:
- 及时移除不再需要的观察者
- 注意防止内存泄漏
- 线程安全:
- 在多线程环境下需要确保观察者列表的线程安全
- 考虑使用线程安全的集合类
- 通知顺序:
- 不要依赖观察者的通知顺序
- 观察者的处理逻辑应该相互独立
- 异常处理:
- 观察者的更新方法应该处理异常
- 一个观察者的异常不应影响其他观察者
使用场景
观察者模式适用于以下场景:
- 当一个对象的改变需要同时改变其他对象时
- 当一个对象必须通知其他对象,而它又不知道这些对象是谁时
- 当一个对象改变时,需要动态更新一组对象时
优点
- 符合开闭原则
- 可以在运行时建立对象之间的关系
- 支持广播通信
缺点
- 观察者模式可能导致广播风暴
- 如果观察者太多,通知的代价会很大
- 观察者之间的依赖关系不易跟踪
总结
观察者模式是一种强大的设计模式,它通过松耦合的方式实现了对象之间的一对多的依赖关系。通过合理使用观察者模式,我们可以构建出灵活、可维护的事件处理系统。在实际应用中,要根据具体场景选择合适的实现方式,并注意处理好各种边界情况。