炒冷饭 - 观察者模式和发布订阅模式

436 阅读2分钟

观察者模式和发布订阅模式

前言

观察者模式和发布订阅模式其实是老生常谈的,但是我们进入vue的源码系列之后,肯定是需要接触到这个的,所以还是需要进行一些了解的

发布订阅、观察者 这两种设计模式的本质是相同的,但是还是由区别的

发布/订阅模式

  • 订阅者
  • 发布者
  • 信号中心

我们假定,存在一个“信号中心”,某个任务知悉完成,就向信号中心“发布”(publish)一个信号,其他任务可以向信号中心 “订阅”(subscribe)这个信号,从而知道什么时候之间可以开始执行。这就叫做“发布\订阅模式”

举个比较简单的例子:

我参加了掘金的年度人气创作者榜单,并且获得了一等奖。

我很期待奖品,天天催着运营这么快递还不发货啊,还不发货啊。

那么现在我们可以直接关注快递的公众号,一旦掘金的运营通过对应的快递发货了,就会通过微信告诉我们,礼品发货了,礼品发货了!

这样其实就是一个发布订阅的过程,这个案例中

  • === 订阅者
  • 运营 === 发布者
  • 微信公众号 === 信号中心 这个概念还是有点抽象的,接下来我们通过代码来表现一下

代码实现

export class EventEmitter {
  constructor() {
    this.sub = {};
  }
  /**
   * 
   * @param {*} methods 要注册的事件的事件名
   * @param {*} handler 事件处理函数
   */
  $on(methods, handler) {
    if (!(methods in this.sub)) {
      this.sub[methods] = [];
    }
    this.sub[methods].push(handler);
  }
  /**
   * 
   * @param {*} methods 要触发的对应事件的事件名
   * @param {*} param 对应事件函数的参数
   */
  $emit(methods, param) {
    if (methods in this.sub) {
      this.sub[methods].forEach((element) => {
        element(param);
      });
    }
  }
}

观察者模式

  • 观察者(订阅者) - Watcher
    • update(): 当事件发生时,具体要做的事情
  • 目标(发布者) - Dep
    • subs数组: 储存所有的观察者
    • addSub():添加观察者
    • notify():当事件发生,调用所有观察者的update()方法
  • 没有事件中心

代码实现

class Dep {
  constructor() {
    this.subs = [];
  }
  addSubs(sub) {
    if (sub?.update) {
      this.subs.push(sub);
    }
  }
  notify() {
    this.subs.forEach((sub) => {
      sub.update();
    });
  }
}
class Watecher {
  update() {
    console.log("更新了");
  }
}
const dep = new Dep();
const watecher = new Watecher();

dep.addSubs(watecher);
dep.notify(watecher);

总结

  • 观察者模式是由具体目标调度,比如事件触发,Dep 就会去调用观察者的方法,所以观察者模式的订阅者与发布者之间是存在依赖的
  • 发布/订阅模式由统一调度中心调用,因此发布者和订阅者不需要知道对方的存在

image.png