1. 中介者模式概述
中介者模式(Mediator Pattern)是一种行为设计模式,它通过定义一个中介对象来封装一组对象之间的交互。这种模式的核心思想是减少对象之间的直接通信依赖,使它们通过中介者进行间接交互,从而降低系统的耦合度。
想象一下机场的塔台控制系统:如果没有塔台作为中介者,所有飞机都需要直接与其他飞机通信来协调起降,这将导致混乱和危险。塔台作为中介者,集中处理所有飞机的请求和状态,确保航空交通有序进行。中介者模式在软件设计中扮演着类似的角色。
2. 中介者模式的结构与实现
2.1 模式参与者
中介者模式通常包含以下核心组件:
- Mediator(抽象中介者):定义中介者的接口,声明与各同事对象交互的方法
- ConcreteMediator(具体中介者):实现抽象中介者接口,协调各同事对象的行为
- Colleague(同事类):定义同事类的接口,通常包含一个指向中介者的引用
- ConcreteColleague(具体同事类):实现同事类接口,与其他同事通过中介者通信
2.2 典型实现代码
以下是一个简单的Java实现示例:
java复制// 抽象中介者
interface Mediator {
void register(Colleague colleague);
void relay(Colleague sender, String message);
}
// 具体中介者
class ConcreteMediator implements Mediator {
private List<Colleague> colleagues = new ArrayList<>();
@Override
public void register(Colleague colleague) {
colleagues.add(colleague);
colleague.setMediator(this);
}
@Override
public void relay(Colleague sender, String message) {
for (Colleague colleague : colleagues) {
if (colleague != sender) {
colleague.receive(message);
}
}
}
}
// 抽象同事类
abstract class Colleague {
protected Mediator mediator;
public void setMediator(Mediator mediator) {
this.mediator = mediator;
}
public abstract void send(String message);
public abstract void receive(String message);
}
// 具体同事类
class ConcreteColleagueA extends Colleague {
@Override
public void send(String message) {
System.out.println("同事A发送消息:" + message);
mediator.relay(this, message);
}
@Override
public void receive(String message) {
System.out.println("同事A收到消息:" + message);
}
}
// 具体同事类B类似实现...
3. 中介者模式的应用场景
3.1 典型应用场景
中介者模式特别适用于以下场景:
-
GUI组件交互:在图形用户界面中,多个控件(如按钮、文本框、下拉菜单)需要相互协调。例如,选中某个复选框可能禁用其他几个控件,使用中介者可以避免控件间的直接依赖。
-
聊天应用程序:在多人聊天系统中,用户(同事类)不直接相互发送消息,而是通过聊天服务器(中介者)进行消息传递。
-
航空交通管制:如前所述,飞机(同事类)通过塔台(中介者)协调飞行路线和起降时间。
-
分布式系统协调:不同服务节点通过中央协调器进行通信,而不是直接相互调用。
3.2 实际案例:订单处理系统
考虑一个电商订单处理系统,涉及库存管理、支付处理、物流调度和客户通知等多个模块。没有中介者时,这些模块会形成复杂的网状依赖关系:
code复制库存管理 → 支付处理
库存管理 → 物流调度
支付处理 → 客户通知
物流调度 → 客户通知
...
引入订单处理中介者后,所有模块只与中介者交互:
code复制[库存管理] → [订单中介者] ← [支付处理]
↑ ↓
[物流调度] ←―――┘ └――→ [客户通知]
这种结构大大简化了系统复杂度,新增模块时只需与中介者建立关系,而不需要修改现有模块。
4. 中介者模式的优缺点分析
4.1 主要优点
-
降低耦合度:将网状交互转换为星型交互,同事对象只需知道中介者,无需知道其他同事。
-
简化对象协议:将多对多交互转化为一对多交互,减少了交互所需的协议数量。
-
控制集中化:将交互复杂性转移到中介者中,使交互更容易理解和维护。
-
复用性提高:由于各同事类之间没有直接关联,可以更方便地复用单个同事类。
4.2 潜在缺点
-
中介者可能变得复杂:随着交互逻辑的增加,中介者可能演变为"上帝对象",承担过多职责。
-
性能考虑:所有通信都经过中介者,在性能敏感的场景可能成为瓶颈。
-
系统设计风险:如果中介者设计不当,可能导致系统难以扩展或修改。
5. 中介者模式的最佳实践
5.1 设计注意事项
-
合理划分责任:确保中介者只处理对象间的交互逻辑,不承担具体的业务功能。
-
避免过度使用:不是所有多对象交互都需要中介者,只有当对象间关系确实复杂时才考虑使用。
-
考虑扩展性:设计中介者接口时,预留足够的灵活性以适应未来的需求变化。
-
命名清晰:中介者类的名称应明确反映其协调的领域,如"OrderProcessor"、"ChatServer"等。
5.2 与其他模式的关系
-
与观察者模式:经常一起使用,中介者可以利用观察者模式实现同事对象间的通知机制。
-
与门面模式:都试图简化复杂交互,但门面模式是为子系统提供简单接口,而中介者是促进子系统内对象间的协作。
-
与代理模式:代理控制对一个对象的访问,而中介者控制多个对象间的交互。
6. 实战案例:聊天室实现
让我们实现一个简单的聊天室系统来演示中介者模式的实际应用:
java复制// 聊天室中介者
class ChatRoom implements Mediator {
private Map<String, User> users = new HashMap<>();
@Override
public void register(User user) {
users.put(user.getName(), user);
}
@Override
public void sendMessage(String sender, String receiver, String message) {
User user = users.get(receiver);
if (user != null) {
user.receive(sender, message);
}
}
}
// 用户类
class User {
private String name;
private Mediator mediator;
public User(String name, Mediator mediator) {
this.name = name;
this.mediator = mediator;
mediator.register(this);
}
public void send(String receiver, String message) {
System.out.println(name + " 发送给 " + receiver + ": " + message);
mediator.sendMessage(name, receiver, message);
}
public void receive(String sender, String message) {
System.out.println(name + " 收到来自 " + sender + " 的消息: " + message);
}
public String getName() {
return name;
}
}
// 使用示例
public class ChatApplication {
public static void main(String[] args) {
ChatRoom chatRoom = new ChatRoom();
User alice = new User("Alice", chatRoom);
User bob = new User("Bob", chatRoom);
User charlie = new User("Charlie", chatRoom);
alice.send("Bob", "你好Bob!");
bob.send("Alice", "你好Alice!");
charlie.send("Bob", "你们在聊什么?");
}
}
在这个实现中:
ChatRoom作为具体中介者,管理所有用户注册和消息路由User作为同事类,不直接与其他用户通信,所有消息通过ChatRoom转发- 新增用户时,只需创建新的
User实例并注册到ChatRoom,无需修改现有代码
7. 中介者模式的变体与扩展
7.1 多级中介者
在复杂系统中,可以设计多级中介者结构。例如,在大型聊天应用中:
- 每个聊天室是一个中介者
- 全局还有一个超级中介者管理所有聊天室
这种分层结构可以避免单一中介者过于复杂。
7.2 事件总线模式
事件总线是中介者模式的一种特殊实现,它使用发布-订阅机制:
- 同事对象发布事件到总线
- 感兴趣的其他同事订阅这些事件
- 总线作为中介者负责事件路由
这种模式在GUI框架和微服务架构中很常见。
7.3 中介者与CQRS
在命令查询职责分离(CQRS)架构中,中介者模式常用于:
- 处理命令的组件作为中介者
- 协调领域模型、持久层和事件发布之间的交互
这种用法可以保持业务逻辑的纯净性。
