javascript设计模式实现之-发布-订阅模式(又称观察者模式)

什么是设计模式?

设计模式是软件开发人员在软件开发过程中面临的一般问题的解决方案。这些解决方案是众多软件开发人员经过相当长的一段时间的试验和错误总结出来的(摘自 菜鸟教程 https://www.runoob.com/design-pattern/design-pattern-tutorial.html)。设计模式最终要达成的目标是让程序的各个模块高内聚,低耦合。

什么是发布订阅模式?

是众多设计模式中的一种,又被称为观察者模式、源-监听者模式。用于定义对象间的一种一对多关系,当一个对象的状态发生改变时,所有依赖它的对象都得到通知并被自动更新。

日常生活中对应场景:

小明最近看上了一套房子,到了售楼处之后才被告知,该楼盘的房子早已售罄。好在售楼MM 告诉小明,不久后还有一些尾盘推出,开发商正在办理相关手续,手续办好后便可以购买。但到底是什么时候,目前还没有人能够知道。后续处理方案如下:
比较不聪明的方式:
于是小明记下了售楼处的电话,以后每天都会打电话过去询问是不是已经到了购买时间。除了小明,还有小红、小强、小龙也会每天向售楼处咨询这个问题。一个星期过后,售楼 MM 决定辞职,因为厌倦了每天回答 1000 个相同内容的电话。
比较聪明的方式(发布订阅者模式):
小明离开之前,把电话号码留在了售楼处。售楼 MM 答应他,新楼盘一推出就马上发信息通知小明。小红、小强和小龙也是一样,他们的电话号码都被记在售楼处的花名册上,新楼盘推出的时候,售楼 MM 会翻开花名册,遍历上面的电话号码,依次发送一条短信来通知他们。有人为这种方式总结出了非常简洁的一句大白话:大家都不要找我,有事我自然会找你们。

以上场景中,小明、小红等都属于订阅者,而售楼MM就属于发布者,此二者间构成一对多的关系。为了让新楼盘推出这一消息更高效地传达到各位订阅者,且当订阅者不再需要该消息时不会被打扰,需要做的事情有如下几步:

  1. 每位订阅者给发布者留下联系电话,实现订阅
  2. 每位订阅者可要求发布者删除自己的电话,从而取消订阅
  3. 新楼盘推出时发布者通知所有订阅者,实现发布

前端开发中典型应用场景:

  • dom事件机制实现
  • Promise实现
  • vue实现

代码实现-自定义事件

class PubSub {
        constructor() {
          // 存放各种自定义事件名及其事件处理函数
          this.handles = {};
        }

        // 订阅  类比 addEventListener()
        on(eventType, handle) {
          if (!this.handles.hasOwnProperty(eventType)) {
            // 一个事件名可能会有多个事件处理函数,多个处理函数存放到数组中
            this.handles[eventType] = [];
          }
          if (typeof handle == 'function') {
            this.handles[eventType].push(handle);
          } else {
            throw new Error('No callback');
          }
          return this;
        }

        // 发布  类比 jQuery中trigger()方法
        emit(eventType, ...args) {
          if (this.handles.hasOwnProperty(eventType)) {
            // 事件发生时,一次执行其对应的所有事件处理函数
            this.handles[eventType].forEach((item, key, arr) => {
              item.apply(null, args);
            });
          } else {
            throw new Error(`"${eventType}"事件未注册`);
          }
          return this;
        }

        // 删除(取消订阅) 移除某个事件处理函数 类比removeEventListener()
        off(eventType, handle) {
          if (!this.handles.hasOwnProperty(eventType)) {
            throw new Error(`"${eventType}"事件未注册`);
          } else if (typeof handle != 'function') {
            throw new Error('No callback');
          } else {
            this.handles[eventType].forEach((item, key, arr) => {
              if (item == handle) {
                arr.splice(key, 1);
              }
            });
          }
          return this; // 实现链式操作
        }
}

// 以下为后续要订阅的一个动作
let callback = function () {
    console.log('you are so nice');
};

let pubsub = new PubSub();
// 订阅
pubsub.on('completed', (...args) => {
          console.log(args.join(' '));
           })
      .on('completed', callback);
       
// 发布
pubsub.emit('completed', 'I love you', 'baby');
pubsub.emit('completed', 'I love you so much!');

输出如下:

I love you baby

you are so nice

I love you so much!

you are so nice

posted @ 2021-11-23 20:51  helloworld777  阅读(222)  评论(0)    收藏  举报