一、模式本质
观察者模式(Observer Pattern)建立对象间的一对多依赖关系,当核心对象(Subject)状态变化时,自动通知所有订阅者(Observers)。
这是一种推模型的典型实现,常用于解耦生产者和消费者。
二、核心实现(TypeScript)
javascript
// 抽象主题接口
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. 复杂表单联动验证
javascript
// 表单字段基类
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消息广播
javascript
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. 复杂状态管理
javascript
// 增强型状态管理
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. 内存泄漏防护
javascript
// 使用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. 批量更新优化
javascript
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. 异步通知处理
javascript
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 |
典型应用 | 对象状态通知 | 系统级别事件 |
内存管理难度 | 较高 | 较低 |
六、最佳实践建议
-
优先使用组合:通过构造函数注入观察者
javascriptclass DataLoader { constructor(private notifier: Subject) {} async load() { try { const data = await fetchData(); this.notifier.setState({ data }); } catch (error) { this.notifier.setState({ error }); } } }
-
防御性编程:添加观察者生命周期管理
javascriptinterface 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); } } } }); } }
-
性能监控:添加观察者执行耗时统计
javascriptclass 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可视为变体实现。