观察者模式定义了对象间的一种一对多的依赖关系。而发布订阅模式是观察者模式的衍生模式,它进一步解耦了发布者与观察者的依赖关系,并且能够更细粒度的控制依赖关系。

观察者模式(Observer)

定义

观察者模式(Observer Pattern):定义了对象间一种一对多的依赖关系,当目标对象 Subject 的状态发生改变时,所有依赖它的对象 Observer 都会得到通知。

模式结构

  1. Subject:目标者对象。
  2. Observer:观察者对象。

Subject与Observer需要一一对应的逻辑耦合方法。由Subject管理订阅、取消订阅方法。

前端代码实现

观察者模式

// 目标者类
class Subject {
  constructor() {}
  addListener(eventName, observer) {
    if (this[eventName]) {
      this[eventName].events.push(observer);
    } else {
      this[eventName] = {
        events: [observer]
      };
    }
    return this;
  }
  removeListener(eventName, observer) {
    const index = this[eventName].events.findIndex(item => item === observer);
    index > -1 && this[eventName].events.splice(index, 1);
    return this;
  }
  publish(eventName) {
    if (this[eventName]) {
      this[eventName].events.forEach(observer => {
        observer.update && observer.update();
      });
    }
  }
}

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

// 实例化两个观察者
let obs1 = new Observer("a", "小明");
let obs2 = new Observer("b", "小红");
let obs3 = new Observer("c", "小懒");

// 向目标者添加观察者
subject.addListener("listen", obs1);
subject.addListener("listen", obs2);
subject.addListener("listen2", obs3);

// 目标者通知更新
subject.publish("listen");
subject.publish("listen2");

发布订阅模式(Publisher && Subscriber)

定义

发布订阅模式:基于一个事件(主题)通道,希望接收通知的对象 Subscriber 通过自定义事件订阅主题,被激活事件的对象 Publisher 通过发布主题事件的方式通知各个订阅该主题的 Subscriber 对象。

模式结构

  1. Subject:目标者对象。
  2. Observer:观察者对象。
  3. Broker:事件中心。

Subject与Observer完全解耦。由Observer管理订阅、取消订阅方法。

前端代码实现

为了便于大家理解,下面代码中创建了Observer观察者类。如果是前端具体的DOM更新场景下,可查看“DOM场景示例”——发布订阅模式

// 目标者类
class Subject {
  constructor() {}
  addListener(eventName, callback) {
    if (this[eventName]) {
      this[eventName].events.push(function() {
        return callback.call(this, eventName);
      });
    } else {
      this[eventName] = {
        events: [
          function() {
            return callback.call(this, eventName);
          }
        ]
      };
    }
    return this;
  }
  removeListener(eventName) {
    delete this[eventName];
    return this;
  }
  publish(eventName, eventIndex) {
    if (this[eventName]) {
      this[eventName].events.forEach(callback => {
        callback && callback();
      });
    }
  }
}

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

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

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

// 事件中心
subject.addListener("gotoclass", function(eventName) {
  obs1.update();
});
subject.addListener("gotoclass", function(eventName) {
  obs2.update();
});

// 目标者通知更新
subject.publish("gotoclass");

冰冰
8 声望0 粉丝

前端工程师