JS設(shè)計模式之中介者模式使用方法詳解
中介者模式(Mediator Pattern)
定義:
是一種行為型設(shè)計模式,用于降低多個對象之間的耦合性。
作用:
中介者模式通過引入一個中介者對象,將對象之間的交互集中管理和控制。
特點:
在中介者模式中,多個對象之間不直接相互通信,而是通過中介者進(jìn)行通信。 中介者對象封裝了對象之間的交互邏輯,各個對象只需要與中介者進(jìn)行通信,而不需要了解其他對象的存在。
參與者:
- 抽象中介者(Abstract Mediator):定義了中介者對象的接口,聲明了對象之間的通信方法。
- 具體中介者(Concrete Mediator):實現(xiàn)了抽象中介者的接口,負(fù)責(zé)協(xié)調(diào)和控制各個對象之間的通信。
- 抽象同事類(Colleague):每個同事類都知道它的中介者對象,并通過中介者對象來與其他同事類進(jìn)行通信。
- 具體同事類(Concrete Colleague):實現(xiàn)了同事類的接口,負(fù)責(zé)處理自己的行為,并與其他同事類通過中介者進(jìn)行通信。
工作流程:
- 定義抽象中介者接口,其中聲明了對象之間的通信方法。
- 定義具體中介者類,實現(xiàn)抽象中介者接口,并負(fù)責(zé)協(xié)調(diào)和控制各個對象之間的通信。
- 定義抽象同事類接口,其中聲明了與中介者進(jìn)行通信的方法。
- 定義具體同事類,實現(xiàn)同事類接口,并實現(xiàn)自己的行為邏輯。
- 在具體同事類中,通過持有中介者對象的引用,通過中介者進(jìn)行與其他同事類的通信。
優(yōu)勢:
- 降低了對象之間的耦合性,使得對象之間的交互更加靈活和可擴(kuò)展。
- 將對象之間的交互邏輯集中管理和控制,減少了代碼的復(fù)雜性。
劣勢:
- 中介者對象可能會變得復(fù)雜,因為它要處理多個對象之間的交互邏輯。
- 引入中介者對象可能會導(dǎo)致系統(tǒng)中對象的數(shù)量增加。
舉例:
假設(shè)我們有一個簡單的聊天室應(yīng)用程序,其中包含多個用戶對象和一個中介者對象來協(xié)調(diào)用戶之間的通信。每個用戶對象都可以發(fā)送消息給其他用戶,并接收其他用戶發(fā)送的消息
首先,定義抽象中介者接口:
abstract class AbstractMediator { // 通信用抽象方法 abstract sendMessage(sender: Colleague, message: string): void; }
然后,定義具體中介者類:
class ChatRoomMediator extends AbstractMediator { users = []; // 中介者收集同事類實例對象 addUser(user: Colleague) { this.users.push(user); } // 實現(xiàn)通信用的抽象方法 sendMessage(sender: Colleague, message: string) { for (let user of this.users) { user !== sender && user.receiveMessage(sender, message); } } }
接下來,定義抽象同事類接口:
abstract class Colleague { constructor(public mediator: AbstractMediator) {} // 作為中介者模式的參與者,每一個同事類對象都具有發(fā)送信息和處理信息的方法 // 不同之處在于發(fā)送信息方法已經(jīng)被抽象類實現(xiàn),而處理信息的方法需要根據(jù)子類的情況定制實現(xiàn) send(message) { this.mediator.sendMessage(this, message); } abstract receiveMessage(sender: Colleague, message: string): void; }
然后,定義具體同事類:
class User extends Colleague { constructor(public name: string, mediator: AbstractMediator) {super(mediator)} receiveMessage(sender: Colleague, message: string) { console.log(`${this.name} received a message from ${sender.name}: ${message}`); } }
最后,在客戶端代碼中創(chuàng)建中介者對象、同事對象; 使用中介者對象收集參與對話的同事對象并進(jìn)行通信示例:
// 創(chuàng)建中介者對象 const chatRoomMediator = new ChatRoomMediator(); // 創(chuàng)建同事對象 // 每一個同事類對象都應(yīng)該保持對中介者對象的引用 const user1 = new User('User 1', chatRoomMediator); const user2 = new User('User 2', chatRoomMediator); const user3 = new User('User 3', chatRoomMediator); // 中介者對象收集同事類對象;其實這里也可以做成new User的時候自動將實例添加到中介者users數(shù)組中去,將具體同事類的構(gòu)造函數(shù)修改成: /* constructor(name: string, mediator: AbstractMediator) { super(mediator); this.name = name; mediator.addUser(this); } */ chatRoomMediator.addUser(user1); chatRoomMediator.addUser(user2); chatRoomMediator.addUser(user3); // 用戶之間通過中介者進(jìn)行通信的示例 user1.send('Hello, everyone!'); user2.send('Hi, User 1!'); user3.send('Nice to meet you all!'); /* >>> User 2 received a message from User 1: Hello, everyone! User 3 received a message from User 1: Hello, everyone! User 1 received a message from User 2: Hi, User 1! User 3 received a message from User 2: Hi, User 1! User 1 received a message from User 3: Nice to meet you all! User 2 received a message from User 3: Nice to meet you all! */
其他應(yīng)用場景:
ws的客戶端和服務(wù)端
- WebSocket(ws)的客戶端和服務(wù)端可以被視為中介者模式中的同事類(Colleague)和具體中介者類(Concrete Mediator)。
- 在WebSocket通信中,客戶端和服務(wù)端之間通過WebSocket協(xié)議進(jìn)行雙向通信。
- 客戶端和服務(wù)端都需要連接到同一個WebSocket服務(wù)器,并通過發(fā)送和接收消息來進(jìn)行通信。在這種情況下,WebSocket服務(wù)器可以充當(dāng)中介者對象,負(fù)責(zé)協(xié)調(diào)和控制客戶端和服務(wù)端之間的通信。
- 客戶端和服務(wù)端可以定義相應(yīng)的發(fā)送和接收方法,通過中介者(WebSocket服務(wù)器)來進(jìn)行通信。
- 客戶端可以通過WebSocket對象的send方法向服務(wù)器發(fā)送消息,而服務(wù)器可以通過WebSocket對象的onmessage事件監(jiān)聽并處理客戶端發(fā)送的消息。
以下是一個簡單的示例代碼,演示了WebSocket客戶端和服務(wù)端之間的通信:
客戶端代碼:
const socket = new WebSocket('ws://localhost:8080'); socket.onopen = () => { console.log('WebSocket connection opened.'); socket.send('Hello, server!'); }; socket.onmessage = (event) => { const message = event.data; console.log('Received message from server:', message); }; socket.onclose = () => { console.log('WebSocket connection closed.'); };
服務(wù)端代碼:
const WebSocket = require('ws'); const wss = new WebSocket.Server({ port: 8080 }); wss.on('connection', (ws) => { console.log('WebSocket connection established.'); ws.on('message', (message) => { console.log('Received message from client:', message); ws.send('Hello, client!'); }); ws.on('close', () => { console.log('WebSocket connection closed.'); }); });
electron的主進(jìn)程和渲染進(jìn)程
- 在 Electron 中,主進(jìn)程(Main Process)和渲染進(jìn)程(Renderer Process)可以被視為中介者模式中的中介類(Concrete Mediator)和同事類(Colleague)。
- 它們之間通過 IPC(Inter-Process Communication)進(jìn)行通信。
- 主進(jìn)程是 Electron 應(yīng)用程序的核心,負(fù)責(zé)管理應(yīng)用程序的生命周期、窗口管理和與系統(tǒng)資源的交互。
- 渲染進(jìn)程是由主進(jìn)程創(chuàng)建的 Web 頁面,每個渲染進(jìn)程都運行在獨立的沙箱環(huán)境中,負(fù)責(zé)顯示和交互用戶界面。
- 主進(jìn)程可以通過 ipcMain 對象監(jiān)聽和處理來自渲染進(jìn)程的消息,而渲染進(jìn)程可以通過 ipcRenderer 對象向主進(jìn)程發(fā)送消息。
以下是一個簡單的示例代碼,演示了 Electron 主進(jìn)程和渲染進(jìn)程之間的通信:
主進(jìn)程代碼:
const { app, BrowserWindow, ipcMain } = require('electron'); let mainWindow; app.on('ready', () => { mainWindow = new BrowserWindow(); mainWindow.loadURL('index.html'); }); ipcMain.on('messageFromRenderer', (event, message) => { console.log('Received message from renderer:', message); event.sender.send('messageToRenderer', 'Hello, renderer!'); });
渲染進(jìn)程代碼(index.html):
<!DOCTYPE html> <html> <body> <script> const { ipcRenderer } = require('electron'); ipcRenderer.send('messageFromRenderer', 'Hello, main process!'); ipcRenderer.on('messageToRenderer', (event, message) => { console.log('Received message from main process:', message); }); </script> </body> </html>
計算機(jī)主板硬件之間的關(guān)系
- 在計算機(jī)硬件中,主板上的元件和總線可以被視為中介者模式中的同事類(Colleague)和具體中介者類(Concrete Mediator)。
- 主板上的各個元件(如處理器、內(nèi)存、顯卡等)之間需要進(jìn)行數(shù)據(jù)傳輸和協(xié)調(diào)工作。
- 這些元件通過總線來進(jìn)行通信,而總線充當(dāng)了中介者的角色,負(fù)責(zé)協(xié)調(diào)和控制元件之間的通信。
- 總線作為中介者對象,將各個元件之間的通信集中管理和控制。元件之間不直接相互通信,而是通過總線進(jìn)行數(shù)據(jù)傳輸和交互。
- 每個元件都知道總線的存在,并通過總線來發(fā)送和接收數(shù)據(jù)。
如下圖所示:
+---------------------+ | Mainboard | +---------------------+ | Processor | | Memory | | GPU | | ... | +---------------------+ | | +---------+ +---| Bus | +---------+
業(yè)務(wù)使用場景:
- 事件中心(Event Centralization):中介者模式可以用于將多個對象的事件處理集中管理。一個中介者對象可以作為事件中心,接收來自多個對象的事件,并根據(jù)需要進(jìn)行廣播或轉(zhuǎn)發(fā)。
class Mediator { constructor() { this.subscribers = []; } subscribe(subscriber) { this.subscribers.push(subscriber); } unsubscribe(subscriber) { this.subscribers = this.subscribers.filter((s) => s !== subscriber); } broadcast(event, data) { for (let subscriber of this.subscribers) { subscriber.handleEvent(event, data); } } } class Subscriber { handleEvent(event, data) { console.log(`Received event '${event}' with data:`, data); } } const mediator = new Mediator(); const subscriber1 = new Subscriber(); mediator.subscribe(subscriber1); const subscriber2 = new Subscriber(); mediator.subscribe(subscriber2); mediator.broadcast('click', { x: 100, y: 200 });
- 表單驗證(Form Validation):中介者模式可以用于對表單中的多個字段進(jìn)行聯(lián)合驗證。每個字段可以通過中介者對象注冊自己的驗證規(guī)則和錯誤處理函數(shù),中介者對象負(fù)責(zé)協(xié)調(diào)和觸發(fā)驗證邏輯
class Mediator { constructor() { this.fields = {}; } registerField(field, validationRules, errorHandle) { this.fields[field] = { validationRules, errorHandle }; } validate() { let isValid = true; for (let field in this.fields) { const { validationRules, errorHandle } = this.fields[field]; const value = document.getElementById(field).value; for (let rule of validationRules) { if (!rule.test(value)) { errorHandle(field); isValid = false; break; } } } return isValid; } } const mediator = new Mediator(); mediator.registerField( 'username', [/.{5,}/], (field) => console.log(`Invalid value for field '${field}'.`) ); mediator.registerField( 'password', [/.{8,}/, /[A-Z]/, /[0-9]/], (field) => console.log(`Invalid value for field '${field}'.`) ); document.getElementById('submit-button').addEventListener('click', () => { if (mediator.validate()) { console.log('Form submitted successfully.'); } });
總結(jié):
中介者模式提供了一種可擴(kuò)展和可維護(hù)的方式來處理復(fù)雜的交互關(guān)系,適用于以下情況:
- 系統(tǒng)中多個對象之間存在復(fù)雜的交互關(guān)系,導(dǎo)致耦合度較高。
- 需要將對象之間的交互邏輯集中管理和控制,避免其分散在多個對象中。
以上就是JS設(shè)計模式之中介者模式使用方法詳解的詳細(xì)內(nèi)容,更多關(guān)于JS中介者模式的資料請關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
實例詳解BootStrap的動態(tài)模態(tài)框及靜態(tài)模態(tài)框
要用bootStrap這個框架就必須要重載它的class類,也就是說class要一樣。接下來通過實例代碼給大家介紹BootStrap的動態(tài)模態(tài)框及靜態(tài)模態(tài)框,需要的朋友可以參考下2018-08-08bootstrap響應(yīng)式導(dǎo)航條模板使用詳解(含下拉菜單,彈出框)
這篇文章主要為大家詳細(xì)介紹了bootstrap響應(yīng)式導(dǎo)航條模板使用詳解,含下拉菜單,彈出框效果,具有一定的參考價值,感興趣的小伙伴們可以參考一下2017-11-11bootstrap動態(tài)添加面包屑(breadcrumb)及其響應(yīng)事件的方法
這篇文章主要介紹了bootstrap動態(tài)添加面包屑(breadcrumb)及其響應(yīng)事件的方法,涉及js數(shù)據(jù)傳輸及定義響應(yīng)事件相關(guān)操作技巧,需要的朋友可以參考下2017-05-05原生javascript中this幾種常見用法總結(jié)
這篇文章主要介紹了原生javascript中this幾種常見用法,結(jié)合實例形式總結(jié)分析了JavaScript中this的功能、常見用法及操作注意事項,需要的朋友可以參考下2020-02-02javascript之對系統(tǒng)的toFixed()方法的修正
javascript之對系統(tǒng)的toFixed()方法的修正...2007-05-05