# 观察者模式(Observer)

# 定义

观察者模式定义了一种一对多的依赖关系,让多个观察者对象同时监听某一个目标对象,当这个目标对象的状态发生变化时,会通知所有观察者对象,使它们能够自动更新。 —— Graphic Design Patterns.

# 模式特征

一个目标者对象 Subject,拥有方法:添加 / 删除 / 通知 Observer; 多个观察者对象 Observer,拥有方法:接收 Subject 状态变更通知并处理; 目标对象 Subject 状态变更时,通知所有 Observer。 Subject 添加一系列 Observer, Subject 负责维护与这些 Observer 之间的联系,“你对我有兴趣,我更新就会通知你”。

# 代码实现

// 目标者类
class Subject {
  constructor() {
    this.observers = [];  // 观察者列表
  }
  // 添加
  add(observer) {
    this.observers.push(observer);
  }
  // 删除
  remove(observer) {
    let idx = this.observers.findIndex(item => item === observer);
    idx > -1 && this.observers.splice(idx, 1);
  }
  // 通知
  notify() {
    for (let observer of this.observers) {
      observer.update();
    }
  }
}

// 观察者类
class Observer {
  constructor(name) {
    this.name = name;
  }
  // 目标对象更新时触发的回调
  update() {
    console.log(`目标者通知我更新了,我是:${this.name}`);
  }
}

// 实例化目标者
let subject = new Subject();

// 实例化两个观察者
let obs1 = new Observer('前端开发者');
let obs2 = new Observer('后端开发者');

// 向目标者添加观察者
subject.add(obs1);
subject.add(obs2);

// 目标者通知更新
subject.notify();  
// 输出:
// 目标者通知我更新了,我是前端开发者
// 目标者通知我更新了,我是后端开发者

# 实践

比如我们给按钮绑定click监听事件,其本质就是观察者模式的一种应用:

// 一个主题,一个观察者,主题变化之后触发观察者执行
btn.addEventListener('click', () => { ... })

这里的btn可以看作是我们的目标对象(被观察对象),当它被点击时,也就是它的状态发生了变化,那么它就会通知内部添加的观察者对象,也就是我们通过addEventListener函数添加的两个匿名函数。