中介者设计模式在Js中的使用

中介者模式(Mediator Pattern)

定义:

是一种行为型设计模式,用于降低多个对象之间的耦合性。

作用:

中介者模式通过引入一个中介者对象,将对象之间的交互集中管理和控制。

特点:

在中介者模式中,多个对象之间不直接相互通信,而是通过中介者进行通信。 中介者对象封装了对象之间的交互逻辑,各个对象只需要与中介者进行通信,而不需要了解其他对象的存在。

参与者:

  1. 抽象中介者(Abstract Mediator):定义了中介者对象的接口,声明了对象之间的通信方法。
  2. 具体中介者(Concrete Mediator):实现了抽象中介者的接口,负责协调和控制各个对象之间的通信。
  3. 抽象同事类(Colleague):每个同事类都知道它的中介者对象,并通过中介者对象来与其他同事类进行通信。
  4. 具体同事类(Concrete Colleague):实现了同事类的接口,负责处理自己的行为,并与其他同事类通过中介者进行通信。

工作流程:

  1. 定义抽象中介者接口,其中声明了对象之间的通信方法。
  2. 定义具体中介者类,实现抽象中介者接口,并负责协调和控制各个对象之间的通信。
  3. 定义抽象同事类接口,其中声明了与中介者进行通信的方法。
  4. 定义具体同事类,实现同事类接口,并实现自己的行为逻辑。
  5. 在具体同事类中,通过持有中介者对象的引用,通过中介者进行与其他同事类的通信。

优势:

  • 降低了对象之间的耦合性,使得对象之间的交互更加灵活和可扩展。
  • 将对象之间的交互逻辑集中管理和控制,减少了代码的复杂性。

劣势:

  • 中介者对象可能会变得复杂,因为它要处理多个对象之间的交互逻辑。
  • 引入中介者对象可能会导致系统中对象的数量增加

举例:

假设我们有一个简单的聊天室应用程序,其中包含多个用户对象和一个中介者对象来协调用户之间的通信。每个用户对象都可以发送消息给其他用户,并接收其他用户发送的消息

首先,定义抽象中介者接口:

typescript 复制代码
abstract class AbstractMediator {
  // 通信用抽象方法
  abstract sendMessage(sender: Colleague, message: string): void;
}

然后,定义具体中介者类:

typescript 复制代码
class ChatRoomMediator extends AbstractMediator {
  users = [];
  // 中介者收集同事类实例对象
  addUser(user: Colleague) {
    this.users.push(user);
  }
  // 实现通信用的抽象方法
  sendMessage(sender: Colleague, message: string) {
    for (let user of this.users) {
      user !== sender && user.receiveMessage(sender, message);
    }
  }
}

接下来,定义抽象同事类接口:

typescript 复制代码
abstract class Colleague {
  constructor(public mediator: AbstractMediator) {}
  // 作为中介者模式的参与者,每一个同事类对象都具有发送信息和处理信息的方法
  // 不同之处在于发送信息方法已经被抽象类实现,而处理信息的方法需要根据子类的情况定制实现
  send(message) {
    this.mediator.sendMessage(this, message);
  }

  abstract receiveMessage(sender: Colleague, message: string): void;
}

然后,定义具体同事类:

typescript 复制代码
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}`);
  }
}

最后,在客户端代码中创建中介者对象、同事对象; 使用中介者对象收集参与对话的同事对象并进行通信示例:

typescript 复制代码
// 创建中介者对象
const chatRoomMediator = new ChatRoomMediator();

// 创建同事对象
// 每一个同事类对象都应该保持对中介者对象的引用
const user1 = new User('User 1', chatRoomMediator);
const user2 = new User('User 2', chatRoomMediator);
const user3 = new User('User 3', chatRoomMediator);

// 中介者对象收集同事类对象;其实这里也可以做成new User的时候自动将实例添加到中介者users数组中去,将具体同事类的构造函数修改成:
/*
  constructor(name: string, mediator: AbstractMediator) {
    super(mediator);
    this.name = name;
    mediator.addUser(this);
  }
*/
chatRoomMediator.addUser(user1);
chatRoomMediator.addUser(user2);
chatRoomMediator.addUser(user3);

// 用户之间通过中介者进行通信的示例
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!
*/

其他应用场景:

ws的客户端和服务端

  • WebSocket(ws)的客户端和服务端可以被视为中介者模式中的同事类(Colleague)和具体中介者类(Concrete Mediator)。
  • 在WebSocket通信中,客户端和服务端之间通过WebSocket协议进行双向通信。
  • 客户端和服务端都需要连接到同一个WebSocket服务器,并通过发送和接收消息来进行通信。在这种情况下,WebSocket服务器可以充当中介者对象,负责协调和控制客户端和服务端之间的通信。
  • 客户端和服务端可以定义相应的发送和接收方法,通过中介者(WebSocket服务器)来进行通信。
  • 客户端可以通过WebSocket对象的send方法向服务器发送消息,而服务器可以通过WebSocket对象的onmessage事件监听并处理客户端发送的消息。

以下是一个简单的示例代码,演示了WebSocket客户端和服务端之间的通信:

客户端代码:

javascript 复制代码
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.');
};

服务端代码:

javascript 复制代码
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的主进程和渲染进程

  • 在 Electron 中,主进程(Main Process)和渲染进程(Renderer Process)可以被视为中介者模式中的中介类(Concrete Mediator)和同事类(Colleague)。
  • 它们之间通过 IPC(Inter-Process Communication)进行通信。
  • 主进程是 Electron 应用程序的核心,负责管理应用程序的生命周期、窗口管理和与系统资源的交互。
  • 渲染进程是由主进程创建的 Web 页面,每个渲染进程都运行在独立的沙箱环境中,负责显示和交互用户界面。
  • 主进程可以通过 ipcMain 对象监听和处理来自渲染进程的消息,而渲染进程可以通过 ipcRenderer 对象向主进程发送消息。

以下是一个简单的示例代码,演示了 Electron 主进程和渲染进程之间的通信:

主进程代码:

javascript 复制代码
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!');
});

渲染进程代码(index.html):

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>

计算机主板硬件之间的关系

  • 在计算机硬件中,主板上的元件和总线可以被视为中介者模式中的同事类(Colleague)和具体中介者类(Concrete Mediator)。
  • 主板上的各个元件(如处理器、内存、显卡等)之间需要进行数据传输和协调工作。
  • 这些元件通过总线来进行通信,而总线充当了中介者的角色,负责协调和控制元件之间的通信。
  • 总线作为中介者对象,将各个元件之间的通信集中管理和控制。元件之间不直接相互通信,而是通过总线进行数据传输和交互。
  • 每个元件都知道总线的存在,并通过总线来发送和接收数据。

如下图所示:

plaintext 复制代码
+---------------------+
|      Mainboard      |
+---------------------+
|       Processor     |
|        Memory       |
|        GPU          |
|        ...          |
+---------------------+
         |
         |   +---------+
         +---|  Bus    |
             +---------+

业务使用场景:

  1. 事件中心(Event Centralization):中介者模式可以用于将多个对象的事件处理集中管理。一个中介者对象可以作为事件中心,接收来自多个对象的事件,并根据需要进行广播或转发。
javascript 复制代码
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 });
  1. 表单验证(Form Validation):中介者模式可以用于对表单中的多个字段进行联合验证。每个字段可以通过中介者对象注册自己的验证规则和错误处理函数,中介者对象负责协调和触发验证逻辑。
javascript 复制代码
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.');
  }
});

总结:

中介者模式提供了一种可扩展和可维护的方式来处理复杂的交互关系,适用于以下情况:

  • 系统中多个对象之间存在复杂的交互关系,导致耦合度较高。
  • 需要将对象之间的交互逻辑集中管理和控制,避免其分散在多个对象中。
相关推荐
F-2H25 分钟前
C语言:指针4(常量指针和指针常量及动态内存分配)
java·linux·c语言·开发语言·前端·c++
gqkmiss1 小时前
Chrome 浏览器插件获取网页 iframe 中的 window 对象
前端·chrome·iframe·postmessage·chrome 插件
m0_748247553 小时前
Web 应用项目开发全流程解析与实战经验分享
开发语言·前端·php
m0_748255024 小时前
前端常用算法集合
前端·算法
真的很上进4 小时前
如何借助 Babel+TS+ESLint 构建现代 JS 工程环境?
java·前端·javascript·css·react.js·vue·html
web130933203984 小时前
vue elementUI form组件动态添加el-form-item并且动态添加rules必填项校验方法
前端·vue.js·elementui
NiNg_1_2344 小时前
Echarts连接数据库,实时绘制图表详解
前端·数据库·echarts
如若1235 小时前
对文件内的文件名生成目录,方便查阅
java·前端·python
滚雪球~6 小时前
npm error code ETIMEDOUT
前端·npm·node.js
沙漏无语6 小时前
npm : 无法加载文件 D:\Nodejs\node_global\npm.ps1,因为在此系统上禁止运行脚本
前端·npm·node.js