中介者设计模式在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.');
  }
});

总结:

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

  • 系统中多个对象之间存在复杂的交互关系,导致耦合度较高。
  • 需要将对象之间的交互逻辑集中管理和控制,避免其分散在多个对象中。
相关推荐
aPurpleBerry7 分钟前
JS常用数组方法 reduce filter find forEach
javascript
GIS程序媛—椰子36 分钟前
【Vue 全家桶】7、Vue UI组件库(更新中)
前端·vue.js
DogEgg_00142 分钟前
前端八股文(一)HTML 持续更新中。。。
前端·html
ZL不懂前端1 小时前
Content Security Policy (CSP)
前端·javascript·面试
乐闻x1 小时前
ESLint 使用教程(一):从零配置 ESLint
javascript·eslint
木舟10091 小时前
ffmpeg重复回听音频流,时长叠加问题
前端
王大锤43911 小时前
golang通用后台管理系统07(后台与若依前端对接)
开发语言·前端·golang
我血条子呢1 小时前
[Vue]防止路由重复跳转
前端·javascript·vue.js
黎金安1 小时前
前端第二次作业
前端·css·css3
啦啦右一1 小时前
前端 | MYTED单篇TED词汇学习功能优化
前端·学习