likes
comments
collection
share

《重学JaveScript专栏》发布订阅者模式原来是这样 “搞事情” 的!关于发布订阅者设计模式,相信连那个“一边鼓吹说

作者站长头像
站长
· 阅读数 15

发布订阅者模式

一、导语篇

关于发布订阅者设计模式,相信连那个“一边鼓吹说羡慕你的高薪想入坑,一边却四处打探你消息,很气愤你咋还没跑滴滴去的隔壁老王”都知道吧。如果还有不知道的老王,甚至将其跟观察者模式混为一谈的,我试着用一句话来总结一下:

  • 观察者模式:直接和大厂签
  • 订阅者模式:签大厂的外包公司😭

(什么?还没明白?那我们的故事就可以开始了...如果有读到文末还没掌握发布订阅者模式的老王,你可以来古都长安我请客,楼下的兄弟们掏钱😏)

二、理念篇

谈到发布订阅者模式,自然离不开发布者订阅者事件中心发布者就好比我们人尽皆知的人类高质量狗仔代表卓某,订阅者就是你们这些八卦迷们。

假如,卓某因出差穿越到了古代,那时候没有网络没有电话,他每次有劲爆消息都需要四处奔走相告,而且还需要记住每一个八卦迷们的信息(个人理解有点类似观察者模式,如果不准确勿喷),这不还没坚持几天他已经受不了了,提出要赶快结束出差回去高效地工作,毕竟养老金还没交够呢。

回来后的他,终于再也无需到处奔走了,更无需记住都有谁对他的八卦感兴趣,他只需在某博或者其它网络平台上点一下按钮发布一下,网络平台(事件中心)就会自动根据订阅者提交的订阅方式(订阅者模式的callback)以及感兴趣的话题(订阅者模式中的事件名)并一键推送给所有订阅者们。

废话有点多了,但我相信上面的描述应该是说清楚了什么是发布订阅者模式了。那怎么实现呢?Talk is cheap, show you the code。

三、实践篇

大家一定会困惑,那是先有发布者还是先有订阅者呢?其实也不难理解,你的八卦再有趣最少得有一个人关注吧?不然自导自演也挺没动力是不?当然,肯定是少不了事件中心的统筹调度了。

  • 事件调度中心

事件调度中心中存储着所有订阅者们感兴趣的订阅方式(calllback)和话题(event)

《重学JaveScript专栏》发布订阅者模式原来是这样 “搞事情” 的!关于发布订阅者设计模式,相信连那个“一边鼓吹说

  • 事件订阅者

《重学JaveScript专栏》发布订阅者模式原来是这样 “搞事情” 的!关于发布订阅者设计模式,相信连那个“一边鼓吹说

  • 事件发布者

《重学JaveScript专栏》发布订阅者模式原来是这样 “搞事情” 的!关于发布订阅者设计模式,相信连那个“一边鼓吹说

  • 取消事件订阅

某个话题的八卦听腻了自然需要支持我们取关咯。 《重学JaveScript专栏》发布订阅者模式原来是这样 “搞事情” 的!关于发布订阅者设计模式,相信连那个“一边鼓吹说 现在,我们已经成功创建了一个简易版的事件发布订阅者模式啦哈哈。那到底管不管用呢,我们一起来体验一下。

  • 完整代码如下
/**
 * 发布订阅者模式
 * 介绍:
 * 1. 存在一个事件中心(类似菜鸟驿站):统一接收所有发布者发布的事件,并负责通知所有的订阅者
 * 2. 存在一个发布者(菜鸟驿站发货负责人,对接多个商家集中填单发货):负责发布所有的事件
 * 3. 存在一个订阅者(菜鸟驿站的消费者,callback相当于订阅方式,比如通过短信的方式):当订阅了感兴趣的事件后,会通过订阅者设置的订阅方式自动收到来自发布者的通知
 * @returns {
 *  describe: (event, callback) => {},
 *  publish: (event, data) => {},
 * }
 */
export default function createPubSub() {
  /** 创建一个事件中心:作为中间代理商的角色,接收所有发布者发布的事件,并负责通知所有的订阅者 */
  const subscribers = {};

  /**
   * 订阅事件
   * @param {*} event
   * @param {*} callback
   */
  function describe(event, callback) {
    /** 如果没有订阅者时创建一个空数组,这样发布者就无需做非法格式的判断*/
    if (!subscribers[event]) {
      subscribers[event] = [];
    }
    /** 将订阅者订阅的事件统一存储到事件中心 */
    subscribers[event].push(callback);
  }
  /**
   * 发布事件
   * @param {*} event
   * @param {*} data
   * @returns
   */
  function publish(event, data) {
    // 如果没有任何订阅者订阅事件时,直接返回
    if (!subscribers[event]) {
      return;
    }

    /** 遍历所有订阅者订阅的事件,集中统一发布 */
    subscribers[event]?.forEach((callback) => {
      callback(data);
    });
  }

  /**
   * 取消订阅
   */
  function unSubscribe(event, callback) {
    /** 如果没有订阅者时创建一个空数组,这样发布者就无需做非法格式的判断*/
    if (!subscribers[event]) {
      return;
    }
    /** 将订阅者订阅的事件统一存储到事件中心 */
    subscribers[event] = subscribers[event].filter((cb) => cb !== callback);
  }

  /** 事件中心统一向外公布发布和订阅方法 */
  return {
    describe,
    publish,
    unSubscribe,
  };
}

const pubSub = createPubSub();
const callback = (data) => {
  console.log(666, "订阅者收到来自event的消息", data);
};

// 订阅者订阅事件
pubSub.describe("event", callback);

// 订阅者取消订阅(如果订阅后取消了订阅,则不会收到消息)
pubSub.unSubscribe("event", callback);

// 发布者发布事件(订阅者无需排队,订阅的事件通过事件类型自动关联)
pubSub.publish("event", "哈哈,听闻在腾大开会需要关窗户是真的吗?");
pubSub.publish("event", "啥?只要新建文件夹就能看到别人的照片真的假的?");

四、体验篇

  • 先来订阅一波消息

《重学JaveScript专栏》发布订阅者模式原来是这样 “搞事情” 的!关于发布订阅者设计模式,相信连那个“一边鼓吹说

  • 然后看看八卦迷们能不能收到消息呀?也可以在控制台中在线订阅实时查看推送情况

《重学JaveScript专栏》发布订阅者模式原来是这样 “搞事情” 的!关于发布订阅者设计模式,相信连那个“一边鼓吹说

哈哈哈,显然是立马收到了消息。可是突然有一天你收到了来自女朋友的超强火力压制:成天沉迷八卦成何体统?养老金赚够了么?上次吃黄焖鸡借的贷款还清了么?🙄,于是一键怒删了你的所有关注! 《重学JaveScript专栏》发布订阅者模式原来是这样 “搞事情” 的!关于发布订阅者设计模式,相信连那个“一边鼓吹说 这下好了,整个世界都清净了🙄 ! 《重学JaveScript专栏》发布订阅者模式原来是这样 “搞事情” 的!关于发布订阅者设计模式,相信连那个“一边鼓吹说

五、总结篇

相信通过以上的实践,你是不是发现原来大名鼎鼎高不可测的“发布订阅者模式”也并没有传说中那么可怕哦?当然了,任何设计模式也好算法也好,重要的是深入理解核心思想,实现方法我们可以逐步迭代打磨,因此以上实现方式仅供演示使用也并不完美,还请老王们手下留情轻喷咯。

观察者模式后期为老王们奉上☕️

案例源码

《重学JavaScript专栏》其它文章推荐:

转载自:https://juejin.cn/post/7415659766552625186
评论
请登录