《重学JaveScript专栏》发布订阅者模式原来是这样 “搞事情” 的!关于发布订阅者设计模式,相信连那个“一边鼓吹说
发布订阅者模式
一、导语篇
关于发布订阅者设计模式,相信连那个“一边鼓吹说羡慕你的高薪想入坑,一边却四处打探你消息,很气愤你咋还没跑滴滴去的隔壁老王”都知道吧。如果还有不知道的老王,甚至将其跟观察者模式混为一谈的,我试着用一句话来总结一下:
- 观察者模式:直接和大厂签
- 订阅者模式:签大厂的外包公司😭
(什么?还没明白?那我们的故事就可以开始了...如果有读到文末还没掌握发布订阅者模式的老王,你可以来古都长安我请客,楼下的兄弟们掏钱😏)
二、理念篇
谈到发布订阅者模式,自然离不开发布者、订阅者和事件中心。发布者就好比我们人尽皆知的人类高质量狗仔代表卓某,订阅者就是你们这些八卦迷们。
假如,卓某因出差穿越到了古代,那时候没有网络没有电话,他每次有劲爆消息都需要四处奔走相告,而且还需要记住每一个八卦迷们的信息(个人理解有点类似观察者模式,如果不准确勿喷),这不还没坚持几天他已经受不了了,提出要赶快结束出差回去高效地工作,毕竟养老金还没交够呢。
回来后的他,终于再也无需到处奔走了,更无需记住都有谁对他的八卦感兴趣,他只需在某博或者其它网络平台上点一下按钮发布一下,网络平台(事件中心)就会自动根据订阅者提交的订阅方式(订阅者模式的callback)以及感兴趣的话题(订阅者模式中的事件名)并一键推送给所有订阅者们。
废话有点多了,但我相信上面的描述应该是说清楚了什么是发布订阅者模式了。那怎么实现呢?Talk is cheap, show you the code。
三、实践篇
大家一定会困惑,那是先有发布者还是先有订阅者呢?其实也不难理解,你的八卦再有趣最少得有一个人关注吧?不然自导自演也挺没动力是不?当然,肯定是少不了事件中心的统筹调度了。
事件调度中心
事件调度中心中存储着所有订阅者们感兴趣的订阅方式(calllback)和话题(event)
事件订阅者
事件发布者
取消事件订阅
某个话题的八卦听腻了自然需要支持我们取关咯。
现在,我们已经成功创建了一个简易版的事件发布订阅者模式啦哈哈。那到底管不管用呢,我们一起来体验一下。
完整代码如下
/**
* 发布订阅者模式
* 介绍:
* 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", "啥?只要新建文件夹就能看到别人的照片真的假的?");
四、体验篇
- 先来订阅一波消息
- 然后看看八卦迷们能不能收到消息呀?也可以在控制台中在线订阅实时查看推送情况
哈哈哈,显然是立马收到了消息。可是突然有一天你收到了来自女朋友的超强火力压制:成天沉迷八卦成何体统?养老金赚够了么?上次吃黄焖鸡借的贷款还清了么?🙄,于是一键怒删了你的所有关注!
这下好了,整个世界都清净了🙄 !
五、总结篇
相信通过以上的实践,你是不是发现原来大名鼎鼎高不可测的“发布订阅者模式”也并没有传说中那么可怕哦?当然了,任何设计模式也好算法也好,重要的是深入理解核心思想,实现方法我们可以逐步迭代打磨,因此以上实现方式仅供演示使用也并不完美,还请老王们手下留情轻喷咯。
观察者模式后期为老王们奉上☕️
《重学JavaScript专栏》其它文章推荐:
转载自:https://juejin.cn/post/7415659766552625186