一、訂閱發布模式詳解
訂閱發布模式是一種設計模式,其基本思想是一個對象(被稱為發布者)不需要直接把信息傳遞給另一個對象(被稱為訂閱者),而是通過一個叫做“消息中心”的中介來實現發布者與訂閱者之間的松耦合。
訂閱發布模式可以應用於許多場景,比如在 GUI 應用程序中實現事件驅動編程、在多線程應用程序中進行線程間通信、在松耦合的系統中實現消息傳遞機制等等。
二、觀察者模式和發布訂閱模式的區別
訂閱發布模式與觀察者模式很相似,但是它們有一些重要的區別。觀察者模式中,被觀察者和觀察者之間是直接聯繫的,觀察者會在被觀察者數據變化時被調用,而訂閱發布模式中通過消息中心來傳遞消息,被稱為“松耦合”。
此外,觀察者模式通常只有一個觀察者,而訂閱發布模式可以有多個訂閱者同時接收同一消息。
三、訂閱發布模式有什麼優點
訂閱發布模式有以下優點:
- 松耦合:發布者和訂閱者之間沒有直接的依賴關係,發布者只需要知道消息中心,而訂閱者只需要關注自己感興趣的消息類型。
- 擴展性強:通過新增消息類型可以輕鬆擴展訂閱發布模式。
- 可維護性強:由於發布者和訂閱者之間不存在直接聯繫,因此代碼結構更加清晰,易於維護和修改。
四、訂閱發布模式怎麼寫
在訂閱發布模式中,一般需要實現三部分代碼:
- 消息中心:負責維護消息列表和訂閱列表,還需要實現消息發布和訂閱管理方法。
- 發布者:發布者需要向消息中心註冊自己感興趣的消息類型,並在需要發布消息時通過消息中心發布。
- 訂閱者:訂閱者需要從消息中心訂閱自己感興趣的消息類型,並實現對應的消息處理方法。
五、發布訂閱模式使用場景
訂閱發布模式可以在很多場景中使用:
- 實現 GUI 應用程序中的事件驅動編程
- 多線程應用程序中進行線程間通信
- 松耦合的系統中實現消息傳遞機制
六、訂閱發布模式細解
下面我們通過一個簡單的示例來演示如何實現訂閱發布模式。
1. 消息中心
class MessageCenter {
constructor() {
this.messages = {};
this.subscribers = {};
}
register(message, target) {
if (!this.messages[message]) {
this.messages[message] = [];
}
this.messages[message].push(target);
if (!this.subscribers[target]) {
this.subscribers[target] = [];
}
this.subscribers[target].push(message);
}
unregister(message, target) {
if (!this.messages[message]) {
return;
}
const index = this.messages[message].indexOf(target);
if (index !== -1) {
this.messages[message].splice(index, 1);
}
const subscriberIndex = this.subscribers[target].indexOf(message);
if (subscriberIndex !== -1) {
this.subscribers[target].splice(subscriberIndex, 1);
}
}
publish(message, data) {
if (!this.messages[message]) {
return;
}
this.messages[message].forEach(target => {
target.receiveMessage(message, data);
});
}
getSubscriptions(target) {
return this.subscribers[target] || [];
}
}
消息中心包含了三個屬性:messages、subscribers 和 messagingCenter,用來維護消息列表、訂閱者列表以及消息中心實例。它還定義了四個方法:register()、unregister()、publish() 和 getSubscriptions()。
其中 register() 方法用來向消息中心註冊感興趣的消息類型,unregister() 方法用來取消註冊。publish() 方法用來發布消息,getSubscriptions() 方法用來獲取訂閱者列表。
2. 發布者
class Publisher {
constructor(messageCenter) {
this.messageCenter = messageCenter;
}
publish(message, data) {
this.messageCenter.publish(message, data);
}
subscribe(message) {
this.messageCenter.register(message, this);
}
unsubscribe(message) {
this.messageCenter.unregister(message, this);
}
getSubscriptions() {
return this.messageCenter.getSubscriptions(this);
}
}
發布者包含一個 messageCenter 屬性,用來發送消息。它還定義了三個方法:publish()、subscribe() 和 unsubscribe()。publish() 方法用來發布消息,subscribe() 方法用來訂閱消息,unsubscribe() 方法用來取消訂閱。
3. 訂閱者
class Subscriber {
constructor(name) {
this.name = name;
}
receiveMessage(message, data) {
console.log(`${this.name} received message "${message}" with data:`, data);
}
}
訂閱者包含一個 name 屬性,用來標識它自己。它實現了 receiveMessage() 方法,用來處理接收到的消息。
4. 使用示例
// 創建一個消息中心實例
const messageCenter = new MessageCenter();
// 創建兩個訂閱者實例
const subscriber1 = new Subscriber("Subscriber 1");
const subscriber2 = new Subscriber("Subscriber 2");
// 創建一個發布者實例,並向消息中心註冊一個 "event" 消息類型
const publisher = new Publisher(messageCenter);
publisher.subscribe("event");
// 訂閱者 1 訂閱 "event" 消息類型,並處理消息
subscriber1.getSubscriptions(); // []
subscriber1.receiveMessage = function (message, data) {
console.log(`${this.name} received message "${message}" with data:`, data);
};
subscriber1.subscribe("event");
// 訂閱者 2 訂閱 "event" 消息類型,並處理消息
subscriber2.getSubscriptions(); // []
subscriber2.receiveMessage = function (message, data) {
console.log(`${this.name} received message "${message}" with data:`, data);
};
subscriber2.subscribe("event");
// 發布者發布 "event" 消息類型,並攜帶數據
publisher.publish("event", { foo: "bar" });
// 控制台輸出:
// Subscriber 1 received message "event" with data: { foo: "bar" }
// Subscriber 2 received message "event" with data: { foo: "bar" }
以上代碼創建了一個消息中心實例 messageCenter,兩個訂閱者實例 subscriber1 和 subscriber2,以及一個發布者實例 publisher。發布者向消息中心註冊了 “event” 消息類型,兩個訂閱者訂閱了這個消息類型,並處理了接收到的消息。
七、訂閱發布文件模式
訂閱發布文件模式(也稱為 AMD 模式)是訂閱發布模式的一種變體,它特別適合在 Web 應用程序中使用。下面的代碼示例演示了如何使用訂閱發布文件模式(使用 RequireJS 庫實現):
// module1.js
define(["messageCenter"], function (messageCenter) {
const module1 = {};
module1.doSomething = function () {
messageCenter.publish("event", { foo: "bar" });
};
return module1;
});
// module2.js
define(["messageCenter"], function (messageCenter) {
const module2 = {};
module2.showMessage = function (message, data) {
console.log(`Message "${message}" received with data:`, data);
};
messageCenter.subscribe("event", module2.showMessage);
return module2;
});
// messageCenter.js
define(function () {
const messageCenter = {};
const messages = {};
messageCenter.publish = function (message, data) {
if (!messages[message]) {
return;
}
messages[message].forEach(function (callback) {
callback(data);
});
};
messageCenter.subscribe = function (message, callback) {
if (!messages[message]) {
messages[message] = [];
}
messages[message].push(callback);
};
return messageCenter;
});
// app.js
require(["module1", "module2"], function (module1, module2) {
module1.doSomething();
});
以上代碼中,module1.js 依賴於 messageCenter.js 模塊,用來發布消息;module2.js 也依賴於 messageCenter.js 模塊,用來訂閱消息。在 app.js 中,使用 RequireJS 庫來加載 module1.js 和 module2.js 模塊,並執行 module1.doSomething()。
八、訂閱發布模式 JS 庫
訂閱發布模式是一種常用的設計模式,因此市面上有許多成熟的 JS 庫可供使用。
以下是一些值得推薦的訂閱發布模式相關的 JS 庫:
- PubSubJS:一個輕量級、可靠的訂閱發布庫。
- EventEmitter2:高級事件模塊,具有同步和異步發布,命名空間支持,按需加載的監聽器和錯誤處理等功能。
- postal.js:另一個用於實現消息訂閱/發布的優秀庫,支持 IE6+ 和現代瀏覽器。
- Mediator.js:支持基於模塊的事件中心。
原創文章,作者:IOGP,如若轉載,請註明出處:https://www.506064.com/zh-hant/n/145465.html