实现观察者模式
手写观察者模式并理解其应用场景
问题
什么是观察者模式?如何实现?它和发布订阅模式有什么区别?
解答
观察者模式定义
观察者模式定义了对象间一对多的依赖关系。当一个对象(Subject)状态改变时,所有依赖它的对象(Observer)都会收到通知并自动更新。
基础实现
// 被观察者(Subject)
class Subject {
constructor() {
this.observers = []; // 存储所有观察者
}
// 添加观察者
addObserver(observer) {
this.observers.push(observer);
}
// 移除观察者
removeObserver(observer) {
this.observers = this.observers.filter(obs => obs !== observer);
}
// 通知所有观察者
notify(data) {
this.observers.forEach(observer => observer.update(data));
}
}
// 观察者(Observer)
class Observer {
constructor(name) {
this.name = name;
}
// 收到通知时的处理方法
update(data) {
console.log(`${this.name} 收到通知:`, data);
}
}
// 使用示例
const subject = new Subject();
const observer1 = new Observer('观察者1');
const observer2 = new Observer('观察者2');
subject.addObserver(observer1);
subject.addObserver(observer2);
subject.notify('状态已更新');
// 观察者1 收到通知: 状态已更新
// 观察者2 收到通知: 状态已更新
subject.removeObserver(observer1);
subject.notify('再次更新');
// 观察者2 收到通知: 再次更新
实际应用:数据绑定
// 模拟 Vue 响应式原理
class ReactiveData {
constructor(initialValue) {
this._value = initialValue;
this.observers = [];
}
get value() {
return this._value;
}
set value(newValue) {
if (this._value !== newValue) {
this._value = newValue;
// 值改变时通知所有观察者
this.observers.forEach(fn => fn(newValue));
}
}
// 订阅变化
watch(callback) {
this.observers.push(callback);
// 返回取消订阅的函数
return () => {
this.observers = this.observers.filter(fn => fn !== callback);
};
}
}
// 使用示例
const count = new ReactiveData(0);
// 模拟视图更新
const unwatch = count.watch(value => {
console.log('视图更新,当前值:', value);
});
count.value = 1; // 视图更新,当前值: 1
count.value = 2; // 视图更新,当前值: 2
unwatch(); // 取消订阅
count.value = 3; // 无输出
观察者模式 vs 发布订阅模式
// 发布订阅模式 - 有中间调度中心
class EventEmitter {
constructor() {
this.events = {}; // 事件中心
}
// 订阅事件
on(event, callback) {
if (!this.events[event]) {
this.events[event] = [];
}
this.events[event].push(callback);
}
// 发布事件
emit(event, ...args) {
const callbacks = this.events[event];
if (callbacks) {
callbacks.forEach(cb => cb(...args));
}
}
// 取消订阅
off(event, callback) {
if (this.events[event]) {
this.events[event] = this.events[event].filter(cb => cb !== callback);
}
}
}
// 使用示例
const emitter = new EventEmitter();
// 订阅者不需要知道发布者是谁
emitter.on('userLogin', user => {
console.log('记录日志:', user.name);
});
emitter.on('userLogin', user => {
console.log('发送欢迎邮件:', user.email);
});
// 发布者不需要知道订阅者是谁
emitter.emit('userLogin', { name: '张三', email: 'zhang@example.com' });
// 记录日志: 张三
// 发送欢迎邮件: zhang@example.com
两者区别图示
观察者模式:
Subject ----直接通知----> Observer1
----直接通知----> Observer2
(Subject 和 Observer 相互知道对方)
发布订阅模式:
Publisher --> EventCenter --> Subscriber1
--> Subscriber2
(Publisher 和 Subscriber 完全解耦)
关键点
- 观察者模式:Subject 直接持有 Observer 引用,两者存在依赖关系
- 发布订阅模式:通过事件中心解耦,发布者和订阅者互不知道对方
- 应用场景:DOM 事件、Vue 响应式、Redux 状态管理、Node EventEmitter
- 优点:解耦对象间的依赖,支持广播通信
- 缺点:观察者过多时可能影响性能,调试时难以追踪通知链路
目录