观察者模式与事件驱动
观察者模式是前端最常用的设计模式之一,事件驱动是其典型应用形式。
核心概念
观察者模式
定义对象间一对多的依赖关系,当被观察者状态改变时,所有依赖者收到通知并自动更新。
基本结构
- Subject(主题):被观察对象,维护观察者列表
- Observer(观察者):订阅主题,响应状态变化
基础实现
手动实现
JavaScript
class Subject {
constructor() {
this.observers = [];
}
subscribe(observer) {
this.observers.push(observer);
return () => {
this.observers = this.observers.filter(o => o !== observer);
};
}
notify(data) {
this.observers.forEach(observer => observer.update(data));
}
}
class Observer {
update(data) {
console.log('Received:', data);
}
}
// 使用
const subject = new Subject();
const observer = new Observer();
subject.subscribe(observer);
subject.notify('Hello');
现代实现
JavaScript
class EventEmitter {
constructor() {
this.events = new Map();
}
on(event, callback) {
if (!this.events.has(event)) {
this.events.set(event, new Set());
}
this.events.get(event).add(callback);
return () => this.off(event, callback);
}
off(event, callback) {
this.events.get(event)?.delete(callback);
}
emit(event, ...args) {
this.events.get(event)?.forEach(cb => cb(...args));
}
once(event, callback) {
const wrapper = (...args) => {
callback(...args);
this.off(event, wrapper);
};
this.on(event, wrapper);
}
}
// 使用
const emitter = new EventEmitter();
emitter.on('data', (msg) => console.log(msg));
emitter.emit('data', 'Hello World');
事件驱动架构
DOM事件模型
JavaScript
// 原生事件:浏览器内置的事件驱动
document.addEventListener('click', (e) => {
console.log('Clicked:', e.target);
});
// 自定义事件
const customEvent = new CustomEvent('userAction', {
detail: { action: 'login', userId: 123 }
});
element.dispatchEvent(customEvent);
element.addEventListener('userAction', (e) => {
console.log('User action:', e.detail);
});
Node.js事件
JavaScript
const EventEmitter = require('events');
class MyEmitter extends EventEmitter {}
const myEmitter = new MyEmitter();
myEmitter.on('event', (a, b) => {
console.log(a, b);
});
myEmitter.emit('event', 'a', 'b');
实际应用场景
状态管理
JavaScript
class Store {
constructor(initialState) {
this.state = initialState;
this.listeners = new Set();
}
getState() {
return this.state;
}
setState(newState) {
this.state = { ...this.state, ...newState };
this.listeners.forEach(listener => listener(this.state));
}
subscribe(listener) {
this.listeners.add(listener);
return () => this.listeners.delete(listener);
}
}
// 使用
const store = new Store({ count: 0 });
store.subscribe(state => console.log('State:', state));
store.setState({ count: 1 });
组件通信
JavaScript
// 全局事件总线(Vue)
const eventBus = {
events: {},
on(event, callback) {
(this.events[event] || (this.events[event] = [])).push(callback);
},
emit(event, ...args) {
(this.events[event] || []).forEach(cb => cb(...args));
}
};
// 跨组件通信
eventBus.on('userLogin', (user) => { /* 处理登录 */ });
eventBus.emit('userLogin', { id: 1, name: 'Alice' });
异步流程控制
JavaScript
class TaskQueue {
constructor() {
this.emitter = new EventEmitter();
this.queue = [];
}
add(task) {
this.queue.push(task);
this.emitter.emit('taskAdded', task);
}
process() {
while (this.queue.length) {
const task = this.queue.shift();
task();
this.emitter.emit('taskCompleted', task);
}
this.emitter.emit('allCompleted');
}
}
发布-订阅模式对比
| 特性 | 观察者模式 | 发布-订阅模式 |
|---|---|---|
| 耦合度 | Subject直接通知Observer | 通过Event Channel中转 |
| 通信方式 | 直接通信 | 间接通信 |
| 适用场景 | 一对多、紧密关联 | 分布式、解耦场景 |
| 实现复杂度 | 简单 | 相对复杂 |
JavaScript
// 发布-订阅模式
class PubSub {
constructor() {
this.topics = {};
}
publish(topic, message) {
(this.topics[topic] || []).forEach(sub => sub(message));
}
subscribe(topic, callback) {
if (!this.topics[topic]) this.topics[topic] = [];
this.topics[topic].push(callback);
return () => {
this.topics[topic] = this.topics[topic].filter(cb => cb !== callback);
};
}
}
观察者模式中Subject和Observer直接交互;发布-订阅模式通过消息调度中心解耦。
要点总结
- 核心结构:Subject维护Observer列表,状态变更时通知
- 事件驱动:观察者模式的前端实践形式
- 解耦优势:发布者与订阅者松耦合,易扩展
- 典型应用:状态管理、组件通信、异步流程
- 注意事项:及时取消订阅,避免内存泄漏
存放路径:articles/JS/专家/设计模式与架构思想/观察者模式与事件驱动.md
📝 发现内容有误?点击此处直接编辑