问题定义
如何在对象之间建立一种一对多的依赖关系,使得当一个对象的状态发生改变时,所有依赖它的对象都能收到通知并自动更新?
步骤与流程
- 定义主题接口: 创建一个主题(Subject)接口,包含添加、删除和通知观察者的方法。
- 实现具体主题类: 创建一个具体主题类,实现主题接口,维护观察者列表,并在状态改变时通知观察者。
- 定义观察者接口: 创建一个观察者(Observer)接口,包含更新方法,用于接收主题的通知。
- 实现具体观察者类: 创建一个或多个具体观察者类,实现观察者接口,定义接收到通知后的处理逻辑。
- 建立订阅关系: 在客户端代码中,创建主题和观察者对象,并将观察者对象添加到主题的观察者列表中。
前端示例
// 主题接口
class Subject {
constructor() {
this.observers = [];
}
addObserver(observer) {
this.observers.push(observer);
}
removeObserver(observer) {
this.observers = this.observers.filter(obs => obs !== observer);
}
notifyObservers(data) {
this.observers.forEach(observer => observer.update(data));
}
}
// 具体主题类
class ConcreteSubject extends Subject {
constructor() {
super();
this.state = null;
}
setState(state) {
this.state = state;
this.notifyObservers(state);
}
getState() {
return this.state;
}
}
// 观察者接口
class Observer {
update(data) {
throw new Error("Method 'update()' must be implemented.");
}
}
// 具体观察者类
class ConcreteObserver extends Observer {
constructor(name) {
super();
this.name = name;
}
update(data) {
console.log(`${this.name} received update: ${data}`);
}
}
// 客户端代码
const subject = new ConcreteSubject();
const observer1 = new ConcreteObserver("Observer 1");
const observer2 = new ConcreteObserver("Observer 2");
subject.addObserver(observer1);
subject.addObserver(observer2);
subject.setState("New state");
// Output:
// Observer 1 received update: New state
// Observer 2 received update: New state
subject.removeObserver(observer2);
subject.setState("Another state");
// Output:
// Observer 1 received update: Another state
应用场景
- 事件处理: 使用观察者模式处理用户界面事件,如按钮点击、鼠标移动等。
- 数据绑定: 使用观察者模式实现数据绑定,当数据模型发生改变时,自动更新视图。
- 发布 - 订阅系统: 使用观察者模式构建发布 - 订阅系统,实现异步通信。
- 状态管理: 使用观察者模式管理应用程序的状态,当状态发生改变时,通知相关的组件。
- 日志记录: 使用观察者模式记录应用程序的日志,当发生特定事件时,自动记录日志。
注意事项
- 避免循环依赖: 观察者模式可能会导致循环依赖,需要仔细设计对象之间的依赖关系。
- 内存泄漏: 如果观察者对象没有及时从主题中移除,可能会导致内存泄漏。
- 性能问题: 如果观察者数量过多,可能会导致性能问题,需要考虑优化通知机制。
参考资料
- Refactoring Guru: https://refactoring.guru/design-patterns/observer
- MDN Web Docs: https://developer.mozilla.org/