中介者模式详解
什么是中介者模式?
中介者模式(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() | +----------------+ +----------------+
|
中介者模式的优缺点
优点
- 减少耦合:同事对象之间不再直接相互引用,而是通过中介者进行通信,降低了耦合度。
- 集中控制:将同事对象之间的交互逻辑集中到中介者中,便于管理和维护。
- 简化通信:同事对象只需要与中介者通信,而不需要知道其他同事对象的存在。
- 可扩展性:可以通过添加新的同事类或修改中介者来扩展系统,而不需要修改现有同事类。
- 符合迪米特法则:每个同事对象只与中介者通信,符合”最少知识原则”。
缺点
- 中介者复杂性:中介者可能会变得复杂,因为它需要处理所有同事对象之间的交互。
- 单点故障:中介者成为系统的核心,如果中介者出现问题,整个系统可能会受到影响。
- 性能问题:所有通信都经过中介者,可能会影响系统的性能。
- 维护困难:当同事对象之间的交互逻辑变得复杂时,中介者的维护可能会变得困难。
中介者模式的实现
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 组件交互、微服务架构、游戏开发、事件处理系统等场景中有着广泛的应用。通过合理使用中介者模式,可以使系统的设计更加清晰,代码更加易于维护。
然而,中介者模式也有其局限性,如中介者可能会变得复杂、成为单点故障等。因此,在使用中介者模式时,需要根据具体的场景和需求,权衡其优缺点,做出合理的设计决策。
总之,中介者模式是一种重要的设计模式,掌握它对于构建松耦合、可维护的系统具有重要意义。