3.7 观察者模式
观察者模式(Observer)定义对象间的一对多依赖:当一个对象(主体 Subject)状态改变时,所有依赖它的对象(观察者 Observer)都会自动收到通知并更新。它是“发布-订阅”思想最经典的面向对象表达。
下面的实验让你给若干显示屏切换订阅状态,再点击“通知”,看只有订阅者才会收到推送。
正在加载交互实验...
主体不认识具体观察者
java
interface Observer { void update(float temp); }
class WeatherStation { // Subject
private List<Observer> observers = new ArrayList<>();
public void subscribe(Observer o) { observers.add(o); }
public void unsubscribe(Observer o) { observers.remove(o); }
public void setTemp(float t) {
this.temp = t;
for (Observer o : observers) o.update(t); // 逐个通知
}
}关键:主体只持有 Observer 接口的列表,不知道也不关心具体是手机、网页还是电视在监听。这让你能自由地增删观察者,而主体代码一行都不用改。下面的气象站实验拖动温度,所有在线显示屏即时联动更新。
正在加载交互实验...
正在加载概念检查...
推 vs 拉,以及那些坑
- 推模型:主体把数据直接推给观察者(
update(temp))。简单,但观察者可能收到不需要的数据。
- 拉模型:主体只通知“我变了”,观察者自己来拉所需数据(
update(subject))。更灵活,但耦合略增。
常见陷阱:
- 通知风暴:一次变化触发大量级联更新,性能受损。
- 更新顺序:观察者之间若有隐含依赖,顺序难以保证。
- 内存泄漏:忘记
unsubscribe,主体一直持有观察者引用,对象无法回收(Java 监听器、前端事件常踩)。
正在加载概念检查...
现实回声
从 GUI 事件、EventEmitter,到 RxJS/响应式编程、消息总线、MVC 里视图监听模型——观察者无处不在。理解它的“通知风暴”和“退订泄漏”,能帮你写出更健壮的响应式代码。
正在加载本节练习...