中介者/中间件模式

中介者模式使组件可以通过一个中心点相互交互:中介者(也称中介器或中间件)。

中介器不是直接相互交谈,而是接收请求,并将它们转发!

在 JavaScript 中,中介者通常只不过是一个对象字面量或一个函数。

您可以将此模式与空中交通管制员和飞行员之间的关系进行比较。
飞行员没有直接与彼此交谈,这可能最终会非常混乱,而是与空中交通管制员交谈。
空中交通管制员确保所有飞机都能收到安全飞行所需的信息,而不会撞到其他飞机。

虽然我们希望不是在 JavaScript 中控制飞机,但我们经常不得不处理对象之间的多向数据。

如果有大量组件,组件之间的通信会变得相当混乱。

不让每个对象直接与其他对象对话,导致多对多关系,对象的请求应该由中介处理。

中介器处理这个请求,并将它转发到它需要的地方。


聊天室案例

中介模式的一个很好的用例是聊天室!
聊天室中的用户不会直接相互交谈。 相反,聊天室充当用户之间的中介。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32

class ChatRoom {
  logMessage(user, message) {
    const time = new Date();
    const sender = user.getName();

    console.log(`${time} [${sender}]: ${message}`);
  }
}

class User {
  constructor(name, chatroom) {
    this.name = name;
    this.chatroom = chatroom;
  }

  getName() {
    return this.name;
  }

  send(message) {
    this.chatMediator.logMessage(this, message);
  }
}

const chatroom = new ChatRoom();

const user1 = new User("John Doe", chatroom);
const user2 = new User("Jane Doe", chatroom);

user1.send("Hi there!"); // 2021/12/22 06:49:35 [John Doe]: Hi there! 
user2.send("Hey!"); // 2021/12/22 06:49:35 [Jane Doe]: Hey! 

我们可以创建连接到聊天室的新用户。
每个用户实例都有一个 send 方法,可以使用它来发送消息。


案例分析 Express.js

Express.js 是一种流行的 Web 应用程序服务器框架。

我们可以向用户可以访问的某些路由添加回调。
假设想在用户点击根“/”时向请求添加一个标头。 我们可以在中间件回调中添加这个标头。

const app = require("express")();

app.use("/", (req, res, next) => {
  req.headers["test-header"] = 1234;
  next();
});

next 方法调用 请求-响应 循环中的下一个回调。 实际上是在创建一个位于请求和响应之间的中间件函数链,反之亦然。

让我们添加另一个中间件函数来检查是否正确添加了测试头。
前一个中间件功能添加的更改将在整个链中可见。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14

const app = require("express")();

app.use(
  "/",
  (req, res, next) => {
    req.headers["test-header"] = 1234;
    next();
  },
  (req, res, next) => {
    console.log(`Request has test header: ${!!req.headers["test-header"]}`); // Request has test header: true
    next();
  }
);

Perfect! 我们可以通过一个或多个中间件功能从请求对象一直到响应进行跟踪和修改。

每次用户点击根端点“/”时,都会调用两个中间件回调。


优点

中间件模式通过让所有通信流经一个中心点,使我们可以轻松地简化对象之间的多对多关系。


知识点

  • Generator.prototype.next()

返回一个包含属性 done 和 value 的对象。
该方法也可以通过接受一个参数用以向生成器传值。