JS設(shè)計(jì)模式之中介者模式使用方法詳解
中介者模式(Mediator Pattern)
定義:
是一種行為型設(shè)計(jì)模式,用于降低多個(gè)對(duì)象之間的耦合性。
作用:
中介者模式通過(guò)引入一個(gè)中介者對(duì)象,將對(duì)象之間的交互集中管理和控制。
特點(diǎn):
在中介者模式中,多個(gè)對(duì)象之間不直接相互通信,而是通過(guò)中介者進(jìn)行通信。 中介者對(duì)象封裝了對(duì)象之間的交互邏輯,各個(gè)對(duì)象只需要與中介者進(jìn)行通信,而不需要了解其他對(duì)象的存在。
參與者:
- 抽象中介者(Abstract Mediator):定義了中介者對(duì)象的接口,聲明了對(duì)象之間的通信方法。
- 具體中介者(Concrete Mediator):實(shí)現(xiàn)了抽象中介者的接口,負(fù)責(zé)協(xié)調(diào)和控制各個(gè)對(duì)象之間的通信。
- 抽象同事類(Colleague):每個(gè)同事類都知道它的中介者對(duì)象,并通過(guò)中介者對(duì)象來(lái)與其他同事類進(jìn)行通信。
- 具體同事類(Concrete Colleague):實(shí)現(xiàn)了同事類的接口,負(fù)責(zé)處理自己的行為,并與其他同事類通過(guò)中介者進(jìn)行通信。
工作流程:
- 定義抽象中介者接口,其中聲明了對(duì)象之間的通信方法。
- 定義具體中介者類,實(shí)現(xiàn)抽象中介者接口,并負(fù)責(zé)協(xié)調(diào)和控制各個(gè)對(duì)象之間的通信。
- 定義抽象同事類接口,其中聲明了與中介者進(jìn)行通信的方法。
- 定義具體同事類,實(shí)現(xiàn)同事類接口,并實(shí)現(xiàn)自己的行為邏輯。
- 在具體同事類中,通過(guò)持有中介者對(duì)象的引用,通過(guò)中介者進(jìn)行與其他同事類的通信。
優(yōu)勢(shì):
- 降低了對(duì)象之間的耦合性,使得對(duì)象之間的交互更加靈活和可擴(kuò)展。
- 將對(duì)象之間的交互邏輯集中管理和控制,減少了代碼的復(fù)雜性。
劣勢(shì):
- 中介者對(duì)象可能會(huì)變得復(fù)雜,因?yàn)樗幚矶鄠€(gè)對(duì)象之間的交互邏輯。
- 引入中介者對(duì)象可能會(huì)導(dǎo)致系統(tǒng)中對(duì)象的數(shù)量增加。
舉例:
假設(shè)我們有一個(gè)簡(jiǎn)單的聊天室應(yīng)用程序,其中包含多個(gè)用戶對(duì)象和一個(gè)中介者對(duì)象來(lái)協(xié)調(diào)用戶之間的通信。每個(gè)用戶對(duì)象都可以發(fā)送消息給其他用戶,并接收其他用戶發(fā)送的消息
首先,定義抽象中介者接口:
abstract class AbstractMediator {
// 通信用抽象方法
abstract sendMessage(sender: Colleague, message: string): void;
}然后,定義具體中介者類:
class ChatRoomMediator extends AbstractMediator {
users = [];
// 中介者收集同事類實(shí)例對(duì)象
addUser(user: Colleague) {
this.users.push(user);
}
// 實(shí)現(xiàn)通信用的抽象方法
sendMessage(sender: Colleague, message: string) {
for (let user of this.users) {
user !== sender && user.receiveMessage(sender, message);
}
}
}接下來(lái),定義抽象同事類接口:
abstract class Colleague {
constructor(public mediator: AbstractMediator) {}
// 作為中介者模式的參與者,每一個(gè)同事類對(duì)象都具有發(fā)送信息和處理信息的方法
// 不同之處在于發(fā)送信息方法已經(jīng)被抽象類實(shí)現(xiàn),而處理信息的方法需要根據(jù)子類的情況定制實(shí)現(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)建中介者對(duì)象、同事對(duì)象; 使用中介者對(duì)象收集參與對(duì)話的同事對(duì)象并進(jìn)行通信示例:
// 創(chuàng)建中介者對(duì)象
const chatRoomMediator = new ChatRoomMediator();
// 創(chuàng)建同事對(duì)象
// 每一個(gè)同事類對(duì)象都應(yīng)該保持對(duì)中介者對(duì)象的引用
const user1 = new User('User 1', chatRoomMediator);
const user2 = new User('User 2', chatRoomMediator);
const user3 = new User('User 3', chatRoomMediator);
// 中介者對(duì)象收集同事類對(duì)象;其實(shí)這里也可以做成new User的時(shí)候自動(dòng)將實(shí)例添加到中介者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);
// 用戶之間通過(guò)中介者進(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)用場(chǎng)景:
ws的客戶端和服務(wù)端
- WebSocket(ws)的客戶端和服務(wù)端可以被視為中介者模式中的同事類(Colleague)和具體中介者類(Concrete Mediator)。
- 在WebSocket通信中,客戶端和服務(wù)端之間通過(guò)WebSocket協(xié)議進(jìn)行雙向通信。
- 客戶端和服務(wù)端都需要連接到同一個(gè)WebSocket服務(wù)器,并通過(guò)發(fā)送和接收消息來(lái)進(jìn)行通信。在這種情況下,WebSocket服務(wù)器可以充當(dāng)中介者對(duì)象,負(fù)責(zé)協(xié)調(diào)和控制客戶端和服務(wù)端之間的通信。
- 客戶端和服務(wù)端可以定義相應(yīng)的發(fā)送和接收方法,通過(guò)中介者(WebSocket服務(wù)器)來(lái)進(jìn)行通信。
- 客戶端可以通過(guò)WebSocket對(duì)象的send方法向服務(wù)器發(fā)送消息,而服務(wù)器可以通過(guò)WebSocket對(duì)象的onmessage事件監(jiān)聽(tīng)并處理客戶端發(fā)送的消息。
以下是一個(gè)簡(jiǎn)單的示例代碼,演示了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)。
- 它們之間通過(guò) IPC(Inter-Process Communication)進(jìn)行通信。
- 主進(jìn)程是 Electron 應(yīng)用程序的核心,負(fù)責(zé)管理應(yīng)用程序的生命周期、窗口管理和與系統(tǒng)資源的交互。
- 渲染進(jìn)程是由主進(jìn)程創(chuàng)建的 Web 頁(yè)面,每個(gè)渲染進(jìn)程都運(yùn)行在獨(dú)立的沙箱環(huán)境中,負(fù)責(zé)顯示和交互用戶界面。
- 主進(jìn)程可以通過(guò) ipcMain 對(duì)象監(jiān)聽(tīng)和處理來(lái)自渲染進(jìn)程的消息,而渲染進(jìn)程可以通過(guò) ipcRenderer 對(duì)象向主進(jìn)程發(fā)送消息。
以下是一個(gè)簡(jiǎn)單的示例代碼,演示了 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ì)算機(jī)主板硬件之間的關(guān)系
- 在計(jì)算機(jī)硬件中,主板上的元件和總線可以被視為中介者模式中的同事類(Colleague)和具體中介者類(Concrete Mediator)。
- 主板上的各個(gè)元件(如處理器、內(nèi)存、顯卡等)之間需要進(jìn)行數(shù)據(jù)傳輸和協(xié)調(diào)工作。
- 這些元件通過(guò)總線來(lái)進(jìn)行通信,而總線充當(dāng)了中介者的角色,負(fù)責(zé)協(xié)調(diào)和控制元件之間的通信。
- 總線作為中介者對(duì)象,將各個(gè)元件之間的通信集中管理和控制。元件之間不直接相互通信,而是通過(guò)總線進(jìn)行數(shù)據(jù)傳輸和交互。
- 每個(gè)元件都知道總線的存在,并通過(guò)總線來(lái)發(fā)送和接收數(shù)據(jù)。
如下圖所示:
+---------------------+
| Mainboard |
+---------------------+
| Processor |
| Memory |
| GPU |
| ... |
+---------------------+
|
| +---------+
+---| Bus |
+---------+業(yè)務(wù)使用場(chǎng)景:
- 事件中心(Event Centralization):中介者模式可以用于將多個(gè)對(duì)象的事件處理集中管理。一個(gè)中介者對(duì)象可以作為事件中心,接收來(lái)自多個(gè)對(duì)象的事件,并根據(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 });- 表單驗(yàn)證(Form Validation):中介者模式可以用于對(duì)表單中的多個(gè)字段進(jìn)行聯(lián)合驗(yàn)證。每個(gè)字段可以通過(guò)中介者對(duì)象注冊(cè)自己的驗(yàn)證規(guī)則和錯(cuò)誤處理函數(shù),中介者對(duì)象負(fù)責(zé)協(xié)調(diào)和觸發(fā)驗(yàn)證邏輯
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ù)的方式來(lái)處理復(fù)雜的交互關(guān)系,適用于以下情況:
- 系統(tǒng)中多個(gè)對(duì)象之間存在復(fù)雜的交互關(guān)系,導(dǎo)致耦合度較高。
- 需要將對(duì)象之間的交互邏輯集中管理和控制,避免其分散在多個(gè)對(duì)象中。
以上就是JS設(shè)計(jì)模式之中介者模式使用方法詳解的詳細(xì)內(nèi)容,更多關(guān)于JS中介者模式的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
js 數(shù)組當(dāng)前行添加數(shù)據(jù)方法詳解
這篇文章主要介紹了js 數(shù)組當(dāng)前行添加數(shù)據(jù)方法詳解,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2020-07-07
button沒(méi)寫(xiě)type=button會(huì)導(dǎo)致點(diǎn)擊時(shí)提交
點(diǎn)擊了一個(gè)彈窗中的按鈕,想到彈窗消失了,經(jīng)測(cè)試后發(fā)現(xiàn)button 沒(méi)寫(xiě)type=button會(huì)導(dǎo)致點(diǎn)擊時(shí)提交2014-03-03
JavaScript中Map和Object的區(qū)別詳解
Map 和 Object 都是 JavaScript 中用于存儲(chǔ)鍵值對(duì)的數(shù)據(jù)結(jié)構(gòu),這篇文章主要介紹了JavaScript中Map和Object區(qū)別的相關(guān)資料,文中通過(guò)代碼介紹的非常詳細(xì),需要的朋友可以參考下2025-08-08
js鼠標(biāo)滑過(guò)圖片震動(dòng)特效的方法
這篇文章主要介紹了js鼠標(biāo)滑過(guò)圖片震動(dòng)特效的方法,涉及onMouseOver事件及圖片操作的技巧,具有一定參考借鑒價(jià)值,需要的朋友可以參考下2015-02-02
H5跳轉(zhuǎn)小程序按鈕不顯示(wx-open-launch-weapp)踩坑指南
這篇文章主要給大家介紹了關(guān)于H5跳轉(zhuǎn)小程序按鈕不顯示(wx-open-launch-weapp)踩坑的相關(guān)資料,文中介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2023-02-02
淺談js for循環(huán)輸出i為同一值的問(wèn)題
下面小編就為大家?guī)?lái)一篇淺談js for循環(huán)輸出i為同一值的問(wèn)題。小編覺(jué)得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2017-03-03
使用JavaScript判斷手機(jī)瀏覽器是橫屏還是豎屏問(wèn)題
這篇文章主要介紹了使用JavaScript判斷手機(jī)瀏覽器是橫屏還是豎屏問(wèn)題的相關(guān)資料,非常不錯(cuò),具有參考借鑒價(jià)值,需要的朋友可以參考下2016-08-08
JavaScript中實(shí)現(xiàn)對(duì)象復(fù)制的終極指南
在 JavaScript 開(kāi)發(fā)中,我們經(jīng)常需要復(fù)制一個(gè)對(duì)象或數(shù)組,當(dāng)我們處理像用戶列表、配置項(xiàng)、表單數(shù)據(jù)等復(fù)雜結(jié)構(gòu)時(shí),淺拷貝(shallow copy)常常無(wú)法滿足需求,真正的解決方案是深拷貝,本文將從內(nèi)存原理出發(fā),深入剖析深拷貝的必要性、實(shí)現(xiàn)方式及其局限性2025-11-11
TypeScript中import?type與import的區(qū)別詳析
ES6引入了模塊化,其設(shè)計(jì)思想是在編譯時(shí)就能確定模塊的依賴關(guān)系,以及輸入和輸出的變量,下面這篇文章主要給大家介紹了關(guān)于TypeScript中import?type與import區(qū)別的相關(guān)資料,需要的朋友可以參考下2022-07-07

