观察者模式
观察者模式(Observer Pattern)是一种行为设计模式,定义了对象之间一对多的依赖关系,当一个对象状态发生改变时,所有依赖它的对象都会收到通知并自动更新。这种模式常用于实现分布式事件处理系统。
模式概述
观察者模式也被称为发布-订阅(Publish-Subscribe)模式。在该模式中:
- 主题(Subject):被观察的对象,维护一组观察者,提供添加、删除和通知观察者的方法
- 观察者(Observer):监听主题变化的对象,当收到通知时执行相应的更新操作
观察者模式的结构
角色组成
- Subject(抽象主题):定义主题的接口,包括注册、注销和通知观察者的方法
- ConcreteSubject(具体主题):实现抽象主题接口,维护观察者列表,当状态改变时通知所有观察者
- Observer(抽象观察者):定义观察者的接口,包含更新方法
- ConcreteObserver(具体观察者):实现抽象观察者接口,在收到通知时执行具体的更新逻辑
UML结构图
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
| ┌─────────────────┐ │ Subject │ │ (抽象主题) │ ├─────────────────┤ │ + register() │ │ + unregister() │ │ + notifyAll() │ └────────┬────────┘ │ 继承 ▼ ┌─────────────────┐ │ ConcreteSubject │ │ (具体主题) │ ├─────────────────┤ │ - observers[] │ │ - state │ └────────┬────────┘ │ 通知 ┌────────┼────────┬────────┐ ▼ ▼ ▼ ▼ ┌───────────┐┌───────────┐┌───────────┐┌───────────┐ │ Observer ││ Observer ││ Observer ││ Observer │ │ (观察者) ││ (观察者) ││ (观察者) ││ (观察者) │ ├───────────┤├───────────┤├───────────┤├───────────┤ │ + update()││ + update()││ + update()││ + update()│ └───────────┘└───────────┘└───────────┘└───────────┘
|
观察者模式的实现
基础实现
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101
| public interface Observer { void update(String message); }
public interface Subject { void registerObserver(Observer observer); void unregisterObserver(Observer observer); void notifyObservers(); }
public class ConcreteSubject implements Subject { private List<Observer> observers = new ArrayList<>(); private String state; public String getState() { return state; } public void setState(String state) { this.state = state; notifyObservers(); } @Override public void registerObserver(Observer observer) { observers.add(observer); } @Override public void unregisterObserver(Observer observer) { observers.remove(observer); } @Override public void notifyObservers() { for (Observer observer : observers) { observer.update(state); } } }
public class ConcreteObserverA implements Observer { private String name; public ConcreteObserverA(String name) { this.name = name; } @Override public void update(String message) { System.out.println(name + " 收到消息: " + message); } }
public class ConcreteObserverB implements Observer { private String name; public ConcreteObserverB(String name) { this.name = name; } @Override public void update(String message) { System.out.println(name + " 处理消息: " + message); } }
public class ObserverPatternTest { public static void main(String[] args) { ConcreteSubject subject = new ConcreteSubject(); Observer observerA = new ConcreteObserverA("观察者A"); Observer observerB = new ConcreteObserverB("观察者B"); subject.registerObserver(observerA); subject.registerObserver(observerB); subject.setState("Hello World!"); System.out.println("-------------------"); subject.unregisterObserver(observerA); subject.setState("Hello Observer!"); }
}
|
Java内置观察者模式
Java提供了内置的观察者模式实现:java.util.Observable 和 java.util.Observer。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72
| import java.util.Observable; import java.util.Observer;
public class WeatherData extends Observable { private float temperature; private float humidity; private float pressure; public void measurementsChanged() { setChanged(); notifyObservers(); } public void setMeasurements(float temperature, float humidity, float pressure) { this.temperature = temperature; this.humidity = humidity; this.pressure = pressure; measurementsChanged(); } public float getTemperature() { return temperature; } public float getHumidity() { return humidity; } public float getPressure() { return pressure; } }
public class CurrentConditionsDisplay implements Observer { private float temperature; private float humidity; public CurrentConditionsDisplay(Observable observable) { observable.addObserver(this); } @Override public void update(Observable obs, Object arg) { if (obs instanceof WeatherData) { WeatherData weatherData = (WeatherData) obs; this.temperature = weatherData.getTemperature(); this.humidity = weatherData.getHumidity(); display(); } } public void display() { System.out.println("当前温度: " + temperature + "°C, 湿度: " + humidity + "%"); } }
public class WeatherStation { public static void main(String[] args) { WeatherData weatherData = new WeatherData(); CurrentConditionsDisplay display = new CurrentConditionsDisplay(weatherData); weatherData.setMeasurements(25.5f, 60f, 1013.25f); weatherData.setMeasurements(26.0f, 65f, 1012.75f); }
}
|
观察者模式的优缺点
优点
- 松耦合:主题和观察者之间是松耦合的,彼此不知道对方的具体实现
- 可扩展性:可以随时添加或删除观察者,符合开闭原则
- 广播通信:主题状态改变时,所有观察者都会收到通知
- 职责分离:主题负责维护状态,观察者负责处理更新逻辑
缺点
- 内存泄漏风险:如果观察者注册后没有正确注销,可能导致内存泄漏
- 通知顺序问题:观察者收到通知的顺序不确定
- 性能问题:如果观察者数量过多,通知过程可能会影响性能
观察者模式的应用场景
- GUI事件处理:按钮点击、键盘输入等事件的处理
- 消息队列系统:生产者-消费者模式
- 分布式系统:服务间的事件通知
- 数据绑定:UI组件与数据源的双向绑定
- 日志系统:多个日志处理器监听日志事件
总结
观察者模式是一种非常实用的设计模式,它实现了对象之间的解耦,使得主题和观察者可以独立变化。在实际开发中,我们可以使用Java内置的Observable和Observer,也可以根据需求自定义实现。
使用观察者模式时需要注意:
- 及时注销不再需要的观察者,避免内存泄漏
- 考虑通知的顺序是否会影响业务逻辑
- 对于性能敏感的场景,可以考虑异步通知或批量通知
参考资料