在很多系统中,你会遇到这样的需求:
- 数据变化了,要通知多个模块
- 一个事件发生,需要触发多个动作
- 状态更新后,界面自动刷新
例如:
- 订单状态变化 → 通知用户、更新库存、记录日志
- 配置变更 → 通知多个服务刷新缓存
- 前端数据变化 → 自动更新 UI
如果你这样写:
python
def update():
notify_user()
update_stock()
write_log()
问题很快就会出现:
- 每增加一个功能,就要改原函数
- 模块之间强耦合
- 代码越来越难维护
这正是 观察者模式(Observer) 要解决的问题。
一、观察者模式解决什么问题?
一句话:
定义对象之间的一对多依赖关系,当一个对象状态发生变化时,所有依赖它的对象都会自动收到通知。
关键词:
- 一对多
- 事件通知
- 解耦
- 自动触发
二、核心角色
观察者模式通常包含两个核心角色:
1️⃣ Subject(被观察者)
- 维护观察者列表
- 状态变化时发出通知
2️⃣ Observer(观察者)
- 接收通知
- 执行对应逻辑
结构:
Subject ---> Observer1
---> Observer2
---> Observer3
三、一个典型场景:订单状态通知
假设订单状态发生变化,需要:
- 通知用户
- 更新库存
- 写日志
四、Python 实现观察者模式
1️⃣ 定义观察者接口
python
from abc import ABC, abstractmethod
class Observer(ABC):
@abstractmethod
def update(self, data):
pass
2️⃣ 定义被观察者
python
class Subject:
def __init__(self):
self._observers = []
def attach(self, observer):
self._observers.append(observer)
def detach(self, observer):
self._observers.remove(observer)
def notify(self, data):
for observer in self._observers:
observer.update(data)
3️⃣ 具体观察者
python
class UserNotifier(Observer):
def update(self, data):
print("通知用户:", data)
class StockUpdater(Observer):
def update(self, data):
print("更新库存:", data)
class Logger(Observer):
def update(self, data):
print("记录日志:", data)
4️⃣ 使用方式
python
subject = Subject()
subject.attach(UserNotifier())
subject.attach(StockUpdater())
subject.attach(Logger())
subject.notify("订单已支付")
输出:
通知用户: 订单已支付
更新库存: 订单已支付
记录日志: 订单已支付
五、观察者模式的核心价值
观察者模式本质是:
发布-订阅机制(Publish-Subscribe)
它解决的是:
- 模块之间强耦合
- 扩展困难
- 逻辑分散
改成观察者后:
- 新增功能 → 新增观察者
- 不需要修改原逻辑
六、Python 更简洁的实现(函数版)
在 Python 中,不一定要写类。
可以直接用函数:
python
class Subject:
def __init__(self):
self._observers = []
def subscribe(self, func):
self._observers.append(func)
def notify(self, data):
for func in self._observers:
func(data)
使用:
python
def log(data):
print("日志:", data)
def notify_user(data):
print("用户通知:", data)
subject = Subject()
subject.subscribe(log)
subject.subscribe(notify_user)
subject.notify("订单完成")
更简洁、更 Pythonic。
七、观察者 vs 事件驱动
观察者模式其实就是:
轻量级事件系统
现实中的对应:
- 前端事件监听(addEventListener)
- Node.js EventEmitter
- Django Signals
- 消息队列(升级版)
八、观察者模式的常见问题
1️⃣ 通知顺序问题
观察者执行顺序可能影响结果。
解决:
- 排序
- 优先级机制
2️⃣ 循环依赖
观察者触发 Subject,再触发观察者 → 死循环。
需要:
- 控制触发条件
- 防止递归调用
3️⃣ 性能问题
观察者过多:
- 通知耗时增加
- 可能阻塞主流程
可以:
- 异步处理
- 消息队列
九、真实项目中的应用
非常常见:
1️⃣ 订单系统
状态变化 → 多个模块响应
2️⃣ 配置中心
配置更新 → 通知服务刷新
3️⃣ 前端框架
Vue / React:
- 数据变化 → UI 自动更新
4️⃣ 日志/监控系统
事件触发 → 多个监控模块响应
十、观察者模式优缺点
✅ 优点
- 解耦
- 易扩展
- 符合开闭原则
- 支持事件驱动
❌ 缺点
- 依赖关系不明显(调试困难)
- 通知链条复杂
- 可能影响性能
十一、什么时候使用观察者模式?
适合:
- 一个对象变化 → 多个对象响应
- 需要解耦模块
- 事件驱动系统
不适合:
- 简单调用关系
- 不需要扩展
十二、一句话总结
观察者模式的本质是:
一处变化,多处响应。
换句话说:
不要在一个函数里写所有逻辑,把它们"订阅"出去。