一、模式本质
观察者模式(Observer Pattern)建立对象间的一对多依赖关系,当核心对象(Subject)状态变化时,自动通知所有订阅者(Observers)。
这是一种推模型的典型实现,常用于解耦生产者和消费者。
二、核心实现(TypeScript)
// 抽象主题接口
interface Subject {addObserver(obs: Observer): void;removeObserver(obs: Observer): void;notifyObservers(): void;
}// 具体主题实现
class ConcreteSubject implements Subject {private observers: Observer[] = [];private state: number = 0;// 添加观察者时进行引用校验addObserver(obs: Observer): void {if (!this.observers.includes(obs)) {this.observers.push(obs);} else {console.warn('Observer already exists');}}// 使用过滤器避免splice索引问题removeObserver(obs: Observer): void {const initialLength = this.observers.length;this.observers = this.observers.filter(o => o !== obs);if (initialLength === this.observers.length) {console.warn('Observer not found');}}notifyObservers(): void {// 克隆数组防止迭代过程中被修改const observersCopy = [...this.observers];observersCopy.forEach(obs => obs.update(this.state));}// 业务方法触发状态变化setState(newState: number): void {this.state = newState;this.notifyObservers();}
}// 观察者接口
interface Observer {update(state: number): void;
}// 具体观察者
class ConcreteObserver implements Observer {constructor(private name: string) {}update(state: number): void {console.log(`[${this.name}] Received state update:`, state);// 这里可以触发视图更新等操作}
}
三、应用场景建议
1. 复杂表单联动验证
// 表单字段基类
abstract class FormField {private validators: Validator[] = [];addValidator(v: Validator) {this.validators.push(v);}validate() {const errors = this.validators.map(v => v.validate(this.value));return errors.filter(e => e !== null);}
}// 实际字段实现
class EmailField extends FormField {value: string = '';
}// 验证器接口
interface Validator {validate(value: any): string | null;
}// 使用示例
const emailField = new EmailField();
emailField.addValidator({validate: (value) => !/.+@.+\..+/.test(value) ? 'Invalid email' : null
});
2. WebSocket消息广播
class WebSocketManager implements Subject {private static instance: WebSocketManager;private ws: WebSocket;private observers: Observer[] = [];private constructor() {this.ws = new WebSocket('wss://api.example.com');this.ws.onmessage = (event) => {this.notifyObservers(JSON.parse(event.data));};}static getInstance(): WebSocketManager {if (!this.instance) {this.instance = new WebSocketManager();}return this.instance;}// 实现Subject接口方法...
}
3. 复杂状态管理
// 增强型状态管理
class Store<T> implements Subject {private state: T;private observers: Observer[] = [];constructor(initialState: T) {this.state = initialState;}setState(newState: Partial<T>) {this.state = { ...this.state, ...newState };this.notifyObservers();}// 支持选择器订阅subscribe(selector: (state: T) => any, callback: (value: any) => void) {const observer = {update: () => {const selected = selector(this.state);callback(selected);}};this.addObserver(observer);return () => this.removeObserver(observer);}
}
四、关键注意事项
1. 内存泄漏防护
// 使用WeakMap避免强引用
const observerMap = new WeakMap<Subject, Set<Observer>>();class SafeSubject implements Subject {constructor() {observerMap.set(this, new Set());}addObserver(obs: Observer) {observerMap.get(this)?.add(obs);}// 自动清理无效引用notifyObservers() {const observers = observerMap.get(this);if (!observers) return;for (const obs of observers) {if (typeof obs.update !== 'function') {observers.delete(obs);} else {obs.update(this.state);}}}
}
2. 批量更新优化
class BatchedSubject extends ConcreteSubject {private updateQueue = new Set<Observer>();private isBatching = false;notifyObservers() {if (this.isBatching) return;this.isBatching = true;requestAnimationFrame(() => {super.notifyObservers();this.isBatching = false;this.updateQueue.clear();});}// 重写状态更新方法setState(newState: number) {super.setState(newState);if (this.isBatching) {this.updateQueue.add(...this.observers);}}
}
3. 异步通知处理
class AsyncSubject extends ConcreteSubject {async notifyObservers() {const promises = this.observers.map(async obs => {try {await obs.update(this.state);} catch (error) {console.error('Observer error:', error);}});await Promise.allSettled(promises);}
}
五、模式对比
特性 | 观察者模式 | 发布-订阅模式 |
---|---|---|
耦合程度 | 直接引用 | 通过中间层 |
通信方式 | 同步/异步 | 通常异步 |
关系复杂度 | 1:N | M:N |
典型应用 | 对象状态通知 | 系统级别事件 |
内存管理难度 | 较高 | 较低 |
六、最佳实践建议
-
优先使用组合:通过构造函数注入观察者
class DataLoader {constructor(private notifier: Subject) {}async load() {try {const data = await fetchData();this.notifier.setState({ data });} catch (error) {this.notifier.setState({ error });}} }
-
防御性编程:添加观察者生命周期管理
interface Observer {update(state: any): void;destroy?(): void; }class SafeSubject {private observers = new Set<Observer>();notifyObservers() {this.observers.forEach(obs => {if (typeof obs.update === 'function') {try {obs.update(this.state);} catch (error) {console.error('Observer error:', error);if (typeof obs.destroy === 'function') {obs.destroy();this.observers.delete(obs);}}}});} }
-
性能监控:添加观察者执行耗时统计
class InstrumentedSubject extends ConcreteSubject {notifyObservers() {this.observers.forEach(obs => {const start = performance.now();obs.update(this.state);const duration = performance.now() - start;if (duration > 100) {console.warn(`Slow observer: ${obs.constructor.name} took ${duration}ms`);}});} }
七、常见面试问题
-
如何防止观察者执行阻塞主线程?
- 答:采用异步通知机制,使用微任务队列或Web Worker
-
观察者模式与响应式编程的关系?
- 答:RxJS等库的Observable是观察者模式的演进,增加了流处理能力
-
如何处理观察者之间的依赖关系?
- 答:引入优先级机制或拓扑排序,但需谨慎处理避免循环依赖
-
在Vue/React中的具体应用?
- 答:Vue的响应式系统基于观察者模式,React的Context API可视为变体实现。