Publish/SubScribe(发布/订阅)模式
前言
什么是发布者/订阅模式?
Publish/Subscribe模式使用了一个主题/ 事件通道,这个通道介于希望接收到通知的对象(订阅者)和激活事件的对象之间(发布者)。
实现
class Pubsub { constructor() { this.topics = {}; this.subUid = -1; } // 发布或者广播事件 publish = function (topic, args) { if (!this.topics[topic]) { return false; } let subscribe = this.topics[topic]; let len = subscribe ? subscribe.length : 0; while (len--) { subscribe[len].func(topic, args); } }; // 通过特定的名称和回调函数订阅事件 subscribe = function (topic, func) { if (!this.topics[topic]) { this.topics[topic] = []; } let token = (++this.subUid).toString(); this.topics[topic].push({ token, func, }); return token; }; // 基于订阅上的标记引用,通过特定的topic进行取消订阅 unsubscribe = function (token) { for (let m in this.topics) { if (this.topics[m]) { for (let i = 0; i < this.topics[m].length; i++) { if (this.topics[m][i].token === token) { this.topics[m].splice(i, 1); return token; } } } } return this; }; }
优点
-
Observer模式和Publish/Subscribe模式鼓励我们努力思考应用程序不同部分之间的关系,可以用于将应用程序分解更小、更松散耦合的块,以改进代码管理和潜在的复用。 在使用任何一种模式时,动态关系可以在观察者和目标之间存在。提供了很大的灵活性,当应用程序的不同部分紧密耦合时,这不是很容易实现的。
缺点
-
从订阅者中解耦发布者,它有时会很难保证应用程序的特定部分按照我们期望的运行。 订阅者非常无视彼此的存在,并对变换发布者产生的成本视而不见。由于订阅者和发布者之间的动态关系,很难跟踪以来更新。
应用
利用Publish/Subscribe模式,实现一个简单的消息通知功能。
let pubsub = new Pubsub(); // 简单的消息记录器所有通过订阅者接收到的主题和数据 let messageLogger = function (topics, data) { console.log(topics, data); }; // 订阅者监听订阅的topic,一旦topic进行广播,订阅者就调用回调函数 let subscription = pubsub.subscribe(inbox/newMessage, messageLogger); // 发布者负责发布程序感兴趣的topic 或者通知 pubsub.publish(inbox/newMessage, hello word); // pubsub.publish(inbox/newMessage, [test, a, b, c]); // 这里取消订阅 pubsub.unsubscribe(subscription); // 因为这里取消了订阅,所以后续没法通知到订阅者 pubsub.publish(inbox/newMessage, { sender: hello@baidu.com, body: hey~, });
Observer(观察者)模式和Publish/SubScribe(发布/订阅)模式的区别
-
Observer模式要求希望接收到主题通知的观察者必须订阅内容改变的事件。 Publish/SubScribe模式允许任何订阅者执行适当的事件处理程序来注册和接收发布者发出的通知。
很多人认为,Observer模式和Publish/Subscribe模式是一样的,其实他们还是有很多不同的,他们两者的区别就跟之前是快递员上门送货,后来快递太多了,为了增加效率,分工更明确一点,现在多了个中间站,菜鸟驿站,快递员方便了,这是在规模起来以后自然而然的选择。现在是人主动去拿快递,如果以后连这也嫌弃效率不高,怎么办?再加一层,菜鸟驿站派出机器人送。
他们二者的区别可以参考本文章: