问题定义

如何在对象之间建立一种一对多的依赖关系,使得当一个对象的状态发生改变时,所有依赖它的对象都能收到通知并自动更新?

步骤与流程

  1. 定义主题接口: 创建一个主题(Subject)接口,包含添加、删除和通知观察者的方法。
  2. 实现具体主题类: 创建一个具体主题类,实现主题接口,维护观察者列表,并在状态改变时通知观察者。
  3. 定义观察者接口: 创建一个观察者(Observer)接口,包含更新方法,用于接收主题的通知。
  4. 实现具体观察者类: 创建一个或多个具体观察者类,实现观察者接口,定义接收到通知后的处理逻辑。
  5. 建立订阅关系: 在客户端代码中,创建主题和观察者对象,并将观察者对象添加到主题的观察者列表中。

前端示例

// 主题接口
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

应用场景

  1. 事件处理: 使用观察者模式处理用户界面事件,如按钮点击、鼠标移动等。
  2. 数据绑定: 使用观察者模式实现数据绑定,当数据模型发生改变时,自动更新视图。
  3. 发布 - 订阅系统: 使用观察者模式构建发布 - 订阅系统,实现异步通信。
  4. 状态管理: 使用观察者模式管理应用程序的状态,当状态发生改变时,通知相关的组件。
  5. 日志记录: 使用观察者模式记录应用程序的日志,当发生特定事件时,自动记录日志。

注意事项

  1. 避免循环依赖: 观察者模式可能会导致循环依赖,需要仔细设计对象之间的依赖关系。
  2. 内存泄漏: 如果观察者对象没有及时从主题中移除,可能会导致内存泄漏。
  3. 性能问题: 如果观察者数量过多,可能会导致性能问题,需要考虑优化通知机制。

参考资料