中介者模式详解

什么是中介者模式?

中介者模式(Mediator Pattern)是一种行为型设计模式,它定义了一个中介对象,用于封装一组对象之间的交互,使这些对象不需要直接相互引用,从而降低它们之间的耦合度。

核心概念

  • Mediator(中介者):定义同事对象之间交互的接口,维护同事对象的引用。
  • ConcreteMediator(具体中介者):实现中介者接口,协调同事对象之间的交互。
  • Colleague(同事):定义与其他同事对象交互的接口,维护中介者的引用。
  • ConcreteColleague(具体同事):实现同事接口,通过中介者与其他同事对象交互。

中介者模式的UML图

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
+----------------+       +----------------+
| Mediator |<------| Colleague |
+----------------+ +----------------+
| +mediate() | | -mediator |
| +register() | | +send() |
+----------------+ | +receive() |
^ +----------------+
| ^
| |
+----------------+ +----------------+
| ConcreteMediator| | ConcreteColleague|
+----------------+ +----------------+
| -colleagues | | +send() |
| +mediate() | | +receive() |
| +register() | +----------------+
+----------------+

中介者模式的优缺点

优点

  1. 减少耦合:同事对象之间不再直接相互引用,而是通过中介者进行通信,降低了耦合度。
  2. 集中控制:将同事对象之间的交互逻辑集中到中介者中,便于管理和维护。
  3. 简化通信:同事对象只需要与中介者通信,而不需要知道其他同事对象的存在。
  4. 可扩展性:可以通过添加新的同事类或修改中介者来扩展系统,而不需要修改现有同事类。
  5. 符合迪米特法则:每个同事对象只与中介者通信,符合”最少知识原则”。

缺点

  1. 中介者复杂性:中介者可能会变得复杂,因为它需要处理所有同事对象之间的交互。
  2. 单点故障:中介者成为系统的核心,如果中介者出现问题,整个系统可能会受到影响。
  3. 性能问题:所有通信都经过中介者,可能会影响系统的性能。
  4. 维护困难:当同事对象之间的交互逻辑变得复杂时,中介者的维护可能会变得困难。

中介者模式的实现

C++ 实现

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
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
#include <iostream>
#include <vector>
#include <string>

// 前向声明
class Mediator;

// 同事接口
class Colleague {
protected:
Mediator* mediator;
std::string name;

public:
Colleague(Mediator* mediator, const std::string& name)
: mediator(mediator), name(name) {}

virtual ~Colleague() {}

const std::string& getName() const {
return name;
}

virtual void send(const std::string& message) = 0;
virtual void receive(const std::string& message, const std::string& sender) = 0;
};

// 中介者接口
class Mediator {
public:
virtual ~Mediator() {}

virtual void registerColleague(Colleague* colleague) = 0;
virtual void mediate(const std::string& message, Colleague* sender) = 0;
};

// 具体中介者
class ConcreteMediator : public Mediator {
private:
std::vector<Colleague*> colleagues;

public:
void registerColleague(Colleague* colleague) override {
colleagues.push_back(colleague);
}

void mediate(const std::string& message, Colleague* sender) override {
for (Colleague* colleague : colleagues) {
// 不发送给发送者自己
if (colleague != sender) {
colleague->receive(message, sender->getName());
}
}
}
};

// 具体同事
class ConcreteColleague : public Colleague {
public:
ConcreteColleague(Mediator* mediator, const std::string& name)
: Colleague(mediator, name) {}

void send(const std::string& message) override {
std::cout << name << " sends: " << message << std::endl;
mediator->mediate(message, this);
}

void receive(const std::string& message, const std::string& sender) override {
std::cout << name << " receives from " << sender << ": " << message << std::endl;
}
};

// 测试代码
int main() {
// 创建中介者
ConcreteMediator mediator;

// 创建同事
ConcreteColleague colleague1(&mediator, "Colleague 1");
ConcreteColleague colleague2(&mediator, "Colleague 2");
ConcreteColleague colleague3(&mediator, "Colleague 3");

// 注册同事
mediator.registerColleague(&colleague1);
mediator.registerColleague(&colleague2);
mediator.registerColleague(&colleague3);

// 发送消息
std::cout << "=== Testing Mediator Pattern ===" << std::endl;
colleague1.send("Hello everyone!");
std::cout << std::endl;

colleague2.send("Hi there!");
std::cout << std::endl;

colleague3.send("How are you?");

return 0;
}

Java 实现

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
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
import java.util.ArrayList;
import java.util.List;

// 同事接口
interface Colleague {
void send(String message);
void receive(String message, String sender);
String getName();
}

// 中介者接口
interface Mediator {
void registerColleague(Colleague colleague);
void mediate(String message, Colleague sender);
}

// 具体中介者
class ConcreteMediator implements Mediator {
private List<Colleague> colleagues = new ArrayList<>();

@Override
public void registerColleague(Colleague colleague) {
colleagues.add(colleague);
}

@Override
public void mediate(String message, Colleague sender) {
for (Colleague colleague : colleagues) {
// 不发送给发送者自己
if (colleague != sender) {
colleague.receive(message, sender.getName());
}
}
}
}

// 具体同事
class ConcreteColleague implements Colleague {
private Mediator mediator;
private String name;

public ConcreteColleague(Mediator mediator, String name) {
this.mediator = mediator;
this.name = name;
}

@Override
public String getName() {
return name;
}

@Override
public void send(String message) {
System.out.println(name + " sends: " + message);
mediator.mediate(message, this);
}

@Override
public void receive(String message, String sender) {
System.out.println(name + " receives from " + sender + ": " + message);
}
}

// 测试代码
public class MediatorPatternDemo {
public static void main(String[] args) {
// 创建中介者
ConcreteMediator mediator = new ConcreteMediator();

// 创建同事
ConcreteColleague colleague1 = new ConcreteColleague(mediator, "Colleague 1");
ConcreteColleague colleague2 = new ConcreteColleague(mediator, "Colleague 2");
ConcreteColleague colleague3 = new ConcreteColleague(mediator, "Colleague 3");

// 注册同事
mediator.registerColleague(colleague1);
mediator.registerColleague(colleague2);
mediator.registerColleague(colleague3);

// 发送消息
System.out.println("=== Testing Mediator Pattern ===");
colleague1.send("Hello everyone!");
System.out.println();

colleague2.send("Hi there!");
System.out.println();

colleague3.send("How are you?");
}
}

Python 实现

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
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
# 同事接口
class Colleague:
def __init__(self, mediator, name):
self.mediator = mediator
self.name = name

def send(self, message):
pass

def receive(self, message, sender):
pass

def get_name(self):
return self.name

# 中介者接口
class Mediator:
def register_colleague(self, colleague):
pass

def mediate(self, message, sender):
pass

# 具体中介者
class ConcreteMediator(Mediator):
def __init__(self):
self.colleagues = []

def register_colleague(self, colleague):
self.colleagues.append(colleague)

def mediate(self, message, sender):
for colleague in self.colleagues:
# 不发送给发送者自己
if colleague != sender:
colleague.receive(message, sender.get_name())

# 具体同事
class ConcreteColleague(Colleague):
def send(self, message):
print(f"{self.name} sends: {message}")
self.mediator.mediate(message, self)

def receive(self, message, sender):
print(f"{self.name} receives from {sender}: {message}")

# 测试代码
if __name__ == "__main__":
# 创建中介者
mediator = ConcreteMediator()

# 创建同事
colleague1 = ConcreteColleague(mediator, "Colleague 1")
colleague2 = ConcreteColleague(mediator, "Colleague 2")
colleague3 = ConcreteColleague(mediator, "Colleague 3")

# 注册同事
mediator.register_colleague(colleague1)
mediator.register_colleague(colleague2)
mediator.register_colleague(colleague3)

# 发送消息
print("=== Testing Mediator Pattern ===")
colleague1.send("Hello everyone!")
print()

colleague2.send("Hi there!")
print()

colleague3.send("How are you?")

C# 实现

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
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
using System;
using System.Collections.Generic;

// 同事接口
interface IColleague {
void Send(string message);
void Receive(string message, string sender);
string Name { get; }
}

// 中介者接口
interface IMediator {
void RegisterColleague(IColleague colleague);
void Mediate(string message, IColleague sender);
}

// 具体中介者
class ConcreteMediator : IMediator {
private List<IColleague> colleagues = new List<IColleague>();

public void RegisterColleague(IColleague colleague) {
colleagues.Add(colleague);
}

public void Mediate(string message, IColleague sender) {
foreach (IColleague colleague in colleagues) {
// 不发送给发送者自己
if (colleague != sender) {
colleague.Receive(message, sender.Name);
}
}
}
}

// 具体同事
class ConcreteColleague : IColleague {
private IMediator mediator;
private string name;

public string Name {
get { return name; }
}

public ConcreteColleague(IMediator mediator, string name) {
this.mediator = mediator;
this.name = name;
}

public void Send(string message) {
Console.WriteLine($"{name} sends: {message}");
mediator.Mediate(message, this);
}

public void Receive(string message, string sender) {
Console.WriteLine($"{name} receives from {sender}: {message}");
}
}

// 测试代码
class Program {
static void Main(string[] args) {
// 创建中介者
ConcreteMediator mediator = new ConcreteMediator();

// 创建同事
ConcreteColleague colleague1 = new ConcreteColleague(mediator, "Colleague 1");
ConcreteColleague colleague2 = new ConcreteColleague(mediator, "Colleague 2");
ConcreteColleague colleague3 = new ConcreteColleague(mediator, "Colleague 3");

// 注册同事
mediator.RegisterColleague(colleague1);
mediator.RegisterColleague(colleague2);
mediator.RegisterColleague(colleague3);

// 发送消息
Console.WriteLine("=== Testing Mediator Pattern ===");
colleague1.Send("Hello everyone!");
Console.WriteLine();

colleague2.Send("Hi there!");
Console.WriteLine();

colleague3.Send("How are you?");
}
}

中介者模式的使用场景

1. 多人聊天系统

  • 聊天室:所有用户通过聊天室(中介者)发送和接收消息
  • 群聊:群成员通过群(中介者)进行通信

2. GUI 组件交互

  • 表单验证:表单中的各个组件通过表单(中介者)进行验证和交互
  • 复合组件:复合组件中的子组件通过父组件(中介者)进行通信

3. 微服务架构

  • 服务注册中心:微服务通过注册中心(中介者)发现和通信
  • API 网关:客户端通过 API 网关(中介者)访问后端服务

4. 游戏开发

  • 游戏服务器:游戏客户端通过游戏服务器(中介者)进行通信
  • 游戏对象交互:游戏中的对象通过游戏管理器(中介者)进行交互

5. 事件处理系统

  • 事件总线:组件通过事件总线(中介者)发布和订阅事件
  • 消息队列:生产者和消费者通过消息队列(中介者)进行通信

6. 其他场景

  • 航空管制系统:飞机通过航空管制中心(中介者)进行通信
  • 交通管理系统:车辆通过交通管理中心(中介者)进行通信
  • 分布式系统:节点通过协调器(中介者)进行通信

适合使用中介者模式的问题

1. 当对象之间存在复杂的多对多关系时

例如:

  • 多个 GUI 组件之间的交互
  • 多个微服务之间的通信
  • 多个游戏对象之间的交互

2. 当对象之间的耦合度高,难以维护时

例如:

  • 每个对象都需要引用其他多个对象
  • 对象之间的交互逻辑分散在各个对象中
  • 修改一个对象可能会影响其他多个对象

3. 当需要集中控制对象之间的交互时

例如:

  • 需要对对象之间的交互进行监控或记录
  • 需要对对象之间的交互进行权限控制
  • 需要对对象之间的交互进行事务管理

4. 当需要减少对象之间的直接依赖时

例如:

  • 符合迪米特法则(最少知识原则)
  • 提高系统的可测试性
  • 提高系统的可扩展性

5. 当需要统一管理对象之间的通信时

例如:

  • 需要实现消息的广播
  • 需要实现消息的路由
  • 需要实现消息的过滤

中介者模式的变体

1. 集中式中介者 vs 分布式中介者

  • 集中式中介者:所有通信都经过一个中央中介者
  • 分布式中介者:通信经过多个中介者,每个中介者负责一部分功能

2. 静态中介者 vs 动态中介者

  • 静态中介者:中介者的结构在编译时确定
  • 动态中介者:中介者的结构在运行时动态构建

3. 同步中介者 vs 异步中介者

  • 同步中介者:消息的传递是同步的
  • 异步中介者:消息的传递是异步的

4. 消息中介者 vs 事件中介者

  • 消息中介者:基于消息的传递
  • 事件中介者:基于事件的发布和订阅

5. 中介者与观察者模式结合

中介者作为事件的发布者,同事作为观察者,订阅中介者的事件

实际应用案例

1. Java Swing 的 EventDispatchThread

Java Swing 使用事件分发线程作为中介者,处理 UI 组件之间的事件传递。

2. Spring 的 ApplicationContext

Spring 框架中的 ApplicationContext 作为中介者,管理 bean 之间的依赖注入和事件传递。

3. 消息队列系统

RabbitMQ、Kafka 等消息队列系统作为中介者,实现生产者和消费者之间的通信。

4. 微服务架构中的服务注册与发现

Eureka、Consul 等服务注册中心作为中介者,实现微服务之间的服务发现和通信。

5. 前端框架中的状态管理

Redux、Vuex 等状态管理库作为中介者,管理组件之间的状态共享和通信。

6. 聊天室应用

聊天室服务器作为中介者,实现用户之间的消息传递。

代码优化建议

1. 合理设计中介者的职责

  • 中介者的职责应该明确,避免过于复杂
  • 可以将中介者的职责分解为多个子中介者
  • 可以使用策略模式或模板方法模式来处理不同类型的交互

2. 优化中介者的性能

  • 对于高频通信,可以考虑使用缓存或批处理
  • 对于异步通信,可以使用消息队列或事件总线
  • 可以使用线程池来处理并发请求

3. 提高中介者的可靠性

  • 实现中介者的容错机制,避免单点故障
  • 实现中介者的备份和恢复机制
  • 实现中介者的监控和告警机制

4. 增强中介者的可扩展性

  • 使用依赖注入来管理中介者的依赖
  • 使用插件机制来扩展中介者的功能
  • 使用配置文件来配置中介者的行为

5. 提高代码的可测试性

  • 为中介者和同事编写单元测试
  • 使用模拟对象(Mock)来测试中介者的行为
  • 使用集成测试来测试整个系统的行为

总结

中介者模式是一种有效的设计模式,它通过引入一个中介对象,将对象之间的直接交互转换为通过中介者的间接交互,从而降低了对象之间的耦合度,提高了系统的可维护性和可扩展性。

中介者模式在多人聊天系统、GUI 组件交互、微服务架构、游戏开发、事件处理系统等场景中有着广泛的应用。通过合理使用中介者模式,可以使系统的设计更加清晰,代码更加易于维护。

然而,中介者模式也有其局限性,如中介者可能会变得复杂、成为单点故障等。因此,在使用中介者模式时,需要根据具体的场景和需求,权衡其优缺点,做出合理的设计决策。

总之,中介者模式是一种重要的设计模式,掌握它对于构建松耦合、可维护的系统具有重要意义。