观察者模式是事件驱动、消息通知的底层思想,也是最早接触的设计模式之一。之前写过一篇《设计模式:观察者模式和发布订阅模式的区别?》讲二者的差异,这篇把观察者模式本身系统地补全:它解决什么、怎么实现、和发布订阅到底差在哪。
一、解决什么问题
观察者模式解决的是**"一对多"的状态同步问题**:一个对象的状态变了,需要自动通知依赖它的多个对象。
典型场景:
- 电商下单:下单成功后,要通知库存系统扣库存、通知积分系统加积分、通知短信系统发通知
- 事件监听:按钮点击、消息到达,触发注册的监听器
- 行情推送:股价变了,通知所有订阅的行情面板
核心思想一句话:主题维护一群观察者,状态一变就挨个通知,主题不需要知道"通知谁"以外的细节。
二、观察者模式怎么落地
两个角色:
- 主题(Subject):维护观察者列表,提供
attach(注册)/detach(移除)/notify(通知) - 观察者(Observer):实现统一的
update方法,接收通知
java
// ① 观察者接口
public interface Observer {
void update(String message);
}
// ② 主题:维护观察者列表
public class Subject {
private List<Observer> observers = new ArrayList<>();
public void attach(Observer o) { observers.add(o); }
public void detach(Observer o) { observers.remove(o); }
public void notifyObservers(String message) {
for (Observer o : observers) {
o.update(message); // 挨个通知
}
}
}
// ③ 具体观察者
public class StockObserver implements Observer {
public void update(String message) {
System.out.println("库存系统收到: " + message);
}
}
// 使用
Subject subject = new Subject();
subject.attach(new StockObserver());
subject.attach(new PointsObserver());
subject.notifyObservers("订单已支付"); // 两个观察者都被通知到三、观察者 vs 发布订阅(易混,重点)
这两个经常被混为一谈,核心区别在于"中间有没有一个消息分发器":
| 维度 | 观察者模式 | 发布订阅模式 |
|---|---|---|
| 耦合 | 主题直接持有观察者列表 | 双方互不知道,靠中间层 |
| 中间层 | 无 | 有(EventBus / Message Broker) |
| 执行方式 | 通常同步直接调用 | 通常异步,消息进队列 |
| 类比 | 老师直接点名通知学生 | 广播电台发信号,收音机自己收 |
用 12306 的例子(我之前旧文里详述过):候补购票里,12306 直接维护候补名单逐个通知,是观察者;如果中间加一层"消息分发器",12306 只发班次信息、由分发器去通知订票者,就是发布订阅。
详细的图文对比可以看我旧文《设计模式:观察者模式和发布订阅模式的区别?》。
四、实际应用
观察者模式在现代框架里无处不在,只是换了名字:
- Spring 的事件机制:
ApplicationEvent+@EventListener,发布事件 → 通知监听器 - 消息队列:Kafka、RabbitMQ 的消费模型,本质是发布订阅的放大版(见《Kafka 快速入门》)
- Java 原生:
Observable/Observer(已废弃,因为有局限性,建议自定义)
小结
- 观察者模式解决"一对多"状态同步:主题维护观察者列表,状态一变挨个通知
- 两角色:Subject(维护列表 + 通知)+ Observer(统一 update)
- 与发布订阅的区别:中间有没有消息分发器(直接通知 vs 经中间层解耦)
- 落地:Spring 事件、消息队列都是它的思想延伸
下一步可以看《责任链模式》——它也是"一个请求经过多个处理者",但和观察者"一对多广播"不同,责任链是"多个处理者依次尝试,谁处理谁停"(文章整理中)。想了解"算法可替换"的兄弟模式,看《策略模式》。
