观察者模式
引言
在软件系统中,对象状态变化常需触发连锁反应(如订单支付后更新库存、发送通知)。传统轮询机制导致资源浪费和响应延迟。观察者模式通过建立发布-订阅机制,实现状态变化的精准广播,成为事件驱动架构的核心设计范式。
诞生背景
GoF在《设计模式》中提出观察者模式,解决三大痛点:
- 强耦合:对象直接调用依赖方(如订单类调用库存类)
- 动态依赖:运行时需增减监听对象(如临时添加审计服务)
- 状态同步:多对象需实时获取核心对象变更(如仪表盘更新)
演进过程
- Smalltalk MVC(1970s):Model-View间数据绑定首次实践
- Java AWT事件模型(1997):标准化
addActionListener()接口 - 响应式编程(2010s):RxJava将观察者模式扩展为流处理范式
核心概念
- 主题(Subject):维护观察者列表,提供注册/注销接口
- 观察者(Observer):定义状态更新时的响应接口
- 具体主题(ConcreteSubject):状态变更时通知所有注册观察者
- 具体观察者(ConcreteObserver):实现业务响应逻辑
通用实现
Java 实现
java
// 观察者接口
interface Observer {
void update(String message);
}
// 主题接口
interface Subject {
void register(Observer o);
void unregister(Observer o);
void notifyObservers();
}
// 具体主题:订单系统
class OrderSystem implements Subject {
private List<Observer> observers = new ArrayList<>();
private String status;
public void setStatus(String status) {
this.status = status;
notifyObservers();
}
@Override
public void register(Observer o) {
observers.add(o);
}
@Override
public void unregister(Observer o) {
observers.remove(o);
}
@Override
public void notifyObservers() {
for (Observer o : observers) {
o.update("订单状态变更: " + status);
}
}
}
// 具体观察者:库存服务
class InventoryService implements Observer {
@Override
public void update(String message) {
System.out.println("[库存系统] " + message);
}
}
// 客户端
public class Client {
public static void main(String[] args) {
OrderSystem order = new OrderSystem();
order.register(new InventoryService());
order.setStatus("已支付"); // 自动触发通知
}
}PHP 实现
php
// 观察者接口
interface Observer {
public function update(string $message): void;
}
// 主题接口
interface Subject {
public function register(Observer $o): void;
public function unregister(Observer $o): void;
public function notifyObservers(): void;
}
// 具体主题:新闻发布器
class NewsPublisher implements Subject {
private array $observers = [];
private string $headline;
public function setHeadline(string $headline): void {
$this->headline = $headline;
$this->notifyObservers();
}
public function register(Observer $o): void {
$this->observers[] = $o;
}
public function unregister(Observer $o): void {
$key = array_search($o, $this->observers);
if ($key !== false) unset($this->observers[$key]);
}
public function notifyObservers(): void {
foreach ($this->observers as $observer) {
$observer->update($this->headline);
}
}
}
// 具体观察者:邮件订阅者
class EmailSubscriber implements Observer {
public function update(string $message): void {
echo "[邮件提醒] 最新新闻: $message\n";
}
}
// 客户端
$publisher = new NewsPublisher();
$publisher->register(new EmailSubscriber());
$publisher->setHeadline("PHP 8.4 发布!"); // 自动触发通知应用场景
- 事件驱动系统:GUI按钮点击事件处理
- 状态监控:服务器集群健康状态广播
- 数据同步:数据库主从复制
- 消息中间件:Kafka/RabbitMQ的发布订阅模型
- 响应式UI:前端框架的数据绑定(如Vue.js)
案例:气象站数据广播
Java 实现
java
// 具体主题:气象站
class WeatherStation implements Subject {
private float temperature;
// 实现Subject接口(同前)...
public void setTemperature(float temp) {
this.temperature = temp;
notifyObservers();
}
}
// 具体观察者:手机APP
class MobileApp implements Observer {
@Override
public void update(String message) {
System.out.println("[APP推送] 当前温度: " + message + "℃");
}
}
// 客户端
WeatherStation station = new WeatherStation();
station.register(new MobileApp());
station.setTemperature(26.5f); // 触发广播PHP 实现
php
// 具体主题:股票交易系统
class StockExchange implements Subject {
private float $price;
// 实现Subject接口(同前)...
public function setPrice(float $price): void {
$this->price = $price;
$this->notifyObservers();
}
}
// 具体观察者:交易机器人
class TradingBot implements Observer {
public function update(string $message): void {
echo "[交易机器人] 股价更新: $message\n";
}
}
// 客户端
$exchange = new StockExchange();
$exchange->register(new TradingBot());
$exchange->setPrice(152.37); // 触发广播优点
- 解耦:主题与观察者无直接依赖
- 动态关系:运行时增减观察者
- 广播效率:一次状态变更通知多方
- 开闭原则:新增观察者无需修改主题
缺点
- 更新不可控:观察者可能引发链式更新
- 性能损耗:大量观察者增加通知耗时
- 调试困难:跨对象调用链难以追踪
扩展
- 事件总线:全局事件中心管理跨模块通信(如EventBus)
- 推拉模型:
- 推模式:主题主动发送数据
- 拉模式:观察者按需从主题获取数据
- 消息过滤:主题携带变更类型(如
notify(EventType.UPDATE))
模式协作
- 与中介者模式:观察者处理分布式通信,中介者集中协调
- 与责任链模式:观察者可组成处理链(如日志→审计→告警)
- 与状态模式:状态变更触发观察者通知
延伸思考
- 分布式挑战:跨服务观察需结合消息队列(如Redis Pub/Sub)
- 前端应用:React/Vue的响应式系统基于观察者原理
- 性能优化:异步通知(线程池/事件循环)避免阻塞
总结
观察者模式是状态传播的神经网,通过解耦的发布-订阅机制,实现变更的精准触达。其核心价值在于:构建弹性通信架构与支持动态事件响应。从GUI事件处理到微服务通信,该模式始终是实时系统设计的基石,彰显了“变化即消息”的架构哲学。