# 观察者模块 vs 发布订阅模式

观察者模式中主体和观察者是互相感知的,发布-订阅模式是借助第三方来实现调度的,发布者和订阅者之间互不感知。

有一种比喻:

  • 发布-订阅模式就好像报社, 邮局和个人的关系,报纸的订阅和分发是由邮局来完成的。报社只负责将报纸发送给邮局。
  • 观察者模式就好像 个体奶农和个人的关系。奶农负责统计有多少人订了产品,所以个人都会有一个相同拿牛奶的方法。奶农有新奶了就负责调用这个方法。

【发布-订阅模式】

class PubSub {
  constructor() {
      this.subscribers = []; // 全部订阅者
  }
  
  // 订阅
  subscribe(topic, callback) {
      let callbacks =this.subscribers[topic];
      if(!callbacks) {
          this.subscribers[topic] = [callback];
      }else{
          callbacks.push(callback);
      }
  }
  
  // 发布
  publish(topic, ...args) {
      let callbacks =this.subscribers[topic] || [];
      callbacks.forEach(callback => callback(...args));
  }
}

// 创建事件调度中心,为订阅者和发布者提供调度服务
let pubSub =new PubSub();

// 订阅某个主题
pubSub.subscribe('topic1', console.log);
pubSub.subscribe('topic2', console.log);

// 发布某个主题
pubSub.publish('topic1','I published topic1');
pubSub.publish('topic2','I published topic2');

【观察者模式】

class Subject {
  constructor() {
      this.observers = [];
  }

  add(observer) {
      this.observers.push(observer);
  }

  notify(...args) {
      this.observers.forEach(observer => observer.update(...args));
  }
}

class Observer {
  update(...args) {
      console.log(...args);
  }
}

// 创建观察者
let ob1 =new Observer();
let ob2 =new Observer();
// 创建目标
let sub =new Subject();
// 目标sub添加观察者
sub.add(ob1);
sub.add(ob2);
// 目标sub触发事件
sub.notify('I fired event');

虽然两种模式都存在订阅者和发布者(具体观察者可认为是订阅者、具体目标可认为是发布者),但是观察者模式是由有具体目标调度的,而发布/订阅模式是统一由调度中心调度的,所以观察者模式的订阅者与发布者之间是存在依赖的,而发布/订阅模式则不会。