13. 观察者模式(Observer)
13. 观察者模式(Observer)
问题:一个对象状态变化时,需要自动通知多个依赖对象。
核心:目标维护观察者列表,状态变化时遍历通知。
type Listener<T> = (data: T) => void;
class EventEmitter<Events extends Record<string, unknown>> {
#listeners: { [K in keyof Events]?: Listener<Events[K]>[] } = {};
on<K extends keyof Events>(event: K, fn: Listener<Events[K]>): this {
(this.#listeners[event] ??= []).push(fn);
return this;
}
emit<K extends keyof Events>(event: K, data: Events[K]): void {
(this.#listeners[event] ?? []).forEach(fn => fn(data));
}
}
const bus = new EventEmitter<{ login: string }>();
bus.on('login', user => console.log(`${user} 已登录`));
bus.on('login', user => console.log(`记录日志: ${user} 登录`));
bus.emit('login', '小明');
// 小明 已登录
// 记录日志: 小明 登录package observer
import "fmt"
type Observer interface {
OnNotify(event string, data any)
}
type EventEmitter struct {
listeners map[string][]Observer
}
func NewEventEmitter() *EventEmitter {
return &EventEmitter{listeners: make(map[string][]Observer)}
}
func (e *EventEmitter) On(event string, obs Observer) {
e.listeners[event] = append(e.listeners[event], obs)
}
func (e *EventEmitter) Emit(event string, data any) {
for _, obs := range e.listeners[event] {
obs.OnNotify(event, data)
}
}
// 示例观察者
type Logger struct{}
func (l Logger) OnNotify(event string, data any) {
fmt.Printf("记录日志: %v %v\n", event, data)
}实战场景
- DOM 事件监听:按钮点击、输入变化、滚动、键盘事件都可以被多个监听器订阅。
- 前端响应式系统:状态变化后通知依赖它的渲染函数、计算属性或 watcher 重新执行。
- 事件总线:跨组件、跨模块发送业务事件,例如登录成功后刷新用户信息、关闭弹窗、记录日志。
- 消息通知:订单状态变化后,同时通知库存、物流、积分、邮件和风控模块。
- 数据订阅:实时行情、协作文档、在线状态变化推送给多个 UI 面板。
- 后端领域事件:用户注册、支付成功、发票开具等事件发布后,由多个 handler 各自处理副作用。
- 文件监听:开发服务器监听文件变化,通知编译、刷新浏览器、重新生成路由。
- 表单联动:一个字段变化后,通知依赖字段重新校验、显隐或更新可选项。
- 监控告警:指标超过阈值时,同时触发告警、记录事件、创建工单或执行自愈脚本。
- 插件系统:核心应用发布生命周期事件,插件按需订阅启动、保存、发布、销毁等节点。
DOM 的
addEventListener、Node.js 的EventEmitter、Vue 的响应式系统都是观察者模式。