观察者模式的核心是主题自动通知观察者实现松耦合:主题管理状态与通知调度,观察者实现update响应;JavaScript可用Set实现基础结构,需契约化接口、最小化数据、禁止反向调用。

观察者模式的核心作用,就是让一个对象(主题)状态变化时,自动、透明地通知所有依赖它的对象(观察者),同时不暴露彼此内部实现——这正是“一对多通知”与“松耦合”的本质。
明确两个关键角色的职责
主题(Subject)不是“发消息的人”,而是“状态管理者+通知调度中心”:
- 它持有观察者列表,但不关心每个观察者具体做什么
- 它只在自身关键状态变更后调用 notify(),把数据(如新值、事件名、上下文)传出去
- 它提供 addObserver() 和 removeObserver(),支持运行时动态订阅/退订
观察者(Observer)不是“被动接收者”,而是“响应契约的执行方”:
- 它只需实现统一的 update(data) 方法,收到通知就按需处理
- 它可自行决定是否更新视图、触发计算、写日志或发起请求
- 它甚至可以持有对主题的弱引用,避免循环引用风险
用 JavaScript 快速落地一个可用结构
不需要框架,几行代码就能搭出可扩展基础:
class Subject {
constructor() {
this.observers = new Set(); // 用 Set 避免重复注册
}
addObserver(observer) {
if (typeof observer.update === 'function') {
this.observers.add(observer);
}
}
removeObserver(observer) {
this.observers.delete(observer);
}
notify(data) {
this.observers.forEach(obs => obs.update(data));
}
}
// 观察者只需有 update 方法,无需继承固定类
const logger = { update: msg => console.log('[LOG]', msg) };
const uiUpdater = { update: data => document.getElementById('status').textContent = data };
const bus = new Subject();
bus.addObserver(logger);
bus.addObserver(uiUpdater);
bus.notify('系统已就绪'); // 两者同时响应
避开常见陷阱,保障解耦真实有效
解耦不是靠“没写调用关系”来实现的,而靠三处设计约束:
- 接口契约化:主题只依赖“有 update 方法的对象”,不依赖任何具体类名或模块路径
- 数据最小化:notify 传参应是轻量数据(如 { type: 'save', id: 123 }),而非整个主题实例
- 无反向调用:观察者 update 中不应直接修改主题状态,否则形成隐式强依赖,破坏单向通知流
延伸一步:支持多事件类型更贴近工程实际
真实场景中,一个主题常需发布不同语义事件(如 'userLogin'、'configChange')。可稍作增强:
- 主题内部用 Map
> 按事件名分组管理观察者 - 添加 on(event, observer) 和 emit(event, data) 接口
- 这样 UI 组件可只监听 'dataUpdate',而日志服务监听全部,互不影响

















