设计模式(一)观察者模式

115 阅读1分钟

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

image-20220127110751274

实现

观察者模式的实现实际上就是使用回调模式,当状态变更时,调用回调通知观察者。

class Subject {
  constructor() {
    this.observers = [];
  }
​
  attach(observer) {
    this.observers.push(observer);
  }
​
  detach(observer) {
    this.observers.forEach((item, i) => {
      if (item === observer) {
        this.observers.splice(i, 1);
      }
    });
  }
​
  notify() {
    this.observers.forEach((observer) => {
      observer.update(this);
    });
  }
}
​
class observer {
  constructor() {}
​
  update() {
    console.log("Observer update");
  }
}
​
/* 使用 */
class subSubject extends Subject {
  constructor() {
    super();
    this.state = null;
    this.observers = [];
  }
​
  getState() {
    return this.state;
  }
​
  setState(newState) {
    this.state = newState;
    this.notify();
  }
}
​
class subObserver extends Observer {
  constructor() {
    super();
    this.state = null;
  }
​
  // 重写一个具体的update方法
  update(subject) {
    this.state = subject.getState();
    this.work();
  }
​
  work() {
    console.log("state change callbackFn");
  }
}

应用

假设我们拿到请求得到的数据后,有多个模块添加了回调。如果什么都不考虑可能会直接这样写:

// getAddress 异步请求
// 有三个模块 AB,C 依赖请求的结果
​
getAddress().then(res => {
  const address = res.address;
  A.update(address)
  B.next(address)
  C.change(address)
})

此时如果多了一个模块 D ,同样需要拿到请求结果后进行下一步操作,我们只好去翻请求的代码把 D 模块的调用补上。

getAddress().then(res => {
  const address = res.address;
  A.update(address)
  B.next(address)
  C.change(address)
  D.init(address)
})

可以看到各个模块和获取地址模块耦合严重,ABC 模块有变化或者有新增模块,都需要深入到获取地址的代码去修改。

根据观察者模式的思想代码可以这样写:

const observers = []
// 注册观察者
observers.push(A.update)
observers.push(B.next)
obervers.push(C.change)
​
getAddress().then(res => {
  const address = res.address;
  observers.forEach(update => update(address))
})

可以看到,通过观察者模式的思想我们将添加回调的操作解耦了出来。

参考:

JavaScript 设计模式核⼼原理与应⽤实践

前端的设计模式系列