Java 设计模式之中介者模式:解耦复杂交互的架构艺术(含 UML 图解)
在复杂系统中,当多个对象之间存在频繁交互时,很容易形成 "蜘蛛网" 般的依赖关系 —— 每个对象都需要知道其他多个对象的存在,导致代码耦合度极高,维护和扩展变得异常困难。中介者模式(Mediator Pattern)通过引入一个 "中间协调者",将多对多的交互简化为一对多,从而让系统结构更清晰、更灵活。
什么是中介者模式?
中介者模式属于行为型设计模式,它定义了一个中介对象,用于封装一系列对象之间的交互。通过中介者,各个对象不再需要显式地相互引用,而是通过中介者传递信息,从而降低对象间的耦合度,使它们可以独立地变化。
生活中最典型的中介者例子就是 "空中交通管制系统"—— 多架飞机之间不会直接通信,而是通过地面塔台(中介者)协调飞行路线,避免碰撞;还有 "聊天室",用户发送的消息通过聊天室转发给其他人,用户之间无需直接建立连接。
中介者模式的核心角色与 UML 类图
核心角色
中介者模式包含 4 个核心角色:
- 抽象中介者(Mediator):定义中介者与同事对象交互的接口,通常包含注册同事和转发消息的方法。
- 具体中介者(Concrete Mediator):实现抽象中介者接口,维护所有同事对象的引用,负责协调同事间的交互。
- 抽象同事类(Colleague):定义同事对象的接口,持有中介者的引用,提供与中介者通信的方法。
- 具体同事类(Concrete Colleague):实现抽象同事类,当需要与其他同事交互时,通过中介者完成。
UML 类图
+---------------------+ +----------------------+
| Mediator |<----->| Colleague |
+---------------------+ +----------------------+
| + register(Colleague) | | - mediator: Mediator |
| + send(message, Colleague) | | + send(message) |
+---------------------+ | + receive(message) |
^ +----------------------+
| ^
| |
+---------------------+ +----------------------+
| ConcreteMediator | | ConcreteColleagueA |
+---------------------+ +----------------------+
| - colleagues: List | | + send(message) |
| + register(Colleague) | | + receive(message) |
| + send(message, Colleague) | +----------------------+
+---------------------+ ...
+----------------------+
| ConcreteColleagueB |
+----------------------+
| + send(message) |
| + receive(message) |
+----------------------+
在 UML 图中,中介者与同事是双向关联:中介者需要知道所有同事以便协调,同事也需要知道中介者以便发起交互。
代码实现:聊天室中介者
我们以 "多人聊天室" 为例实现中介者模式:用户(同事)发送的消息通过聊天室(中介者)转发给其他用户,用户之间无需直接通信。
1. 抽象中介者(聊天室接口)
/**
* 抽象中介者:聊天室
*/
public interface ChatRoom {
// 注册用户(添加同事)
void register(User user);
// 转发消息(中介者协调逻辑)
void relayMessage(String message, User sender);
}
2. 具体中介者(具体聊天室)
import java.util.ArrayList;
import java.util.List;
/**
* 具体中介者:微信群聊
*/
public class WeChatGroup implements ChatRoom {
// 维护所有用户(同事)
private List<User> users = new ArrayList<>();
@Override
public void register(User user) {
users.add(user);
}
@Override
public void relayMessage(String message, User sender) {
// 遍历所有用户,将消息转发给除发送者外的其他人
for (User user : users) {
if (!user.equals(sender)) {
user.receive(message, sender.getName());
}
}
}
}
3. 抽象同事类(用户)
/**
* 抽象同事类:用户
*/
public abstract class User {
protected ChatRoom mediator; // 持有中介者引用
protected String name; // 用户名
public User(ChatRoom mediator, String name) {
this.mediator = mediator;
this.name = name;
}
public String getName() {
return name;
}
// 发送消息(通过中介者)
public abstract void send(String message);
// 接收消息
public abstract void receive(String message, String senderName);
}
4. 具体同事类(普通用户)
/**
* 具体同事类:普通用户
*/
public class NormalUser extends User {
public NormalUser(ChatRoom mediator, String name) {
super(mediator, name);
}
@Override
public void send(String message) {
System.out.println(name + "发送消息:" + message);
// 不直接调用其他用户,而是通过中介者转发
mediator.relayMessage(message, this);
}
@Override
public void receive(String message, String senderName) {
System.out.println(name + "收到来自" + senderName + "的消息:" + message);
}
}
5. 客户端使用
public class Client {
public static void main(String[] args) {
// 创建中介者:微信群聊
ChatRoom weChatGroup = new WeChatGroup();
// 创建同事:用户
User alice = new NormalUser(weChatGroup, "Alice");
User bob = new NormalUser(weChatGroup, "Bob");
User charlie = new NormalUser(weChatGroup, "Charlie");
// 用户加入群聊(注册到中介者)
weChatGroup.register(alice);
weChatGroup.register(bob);
weChatGroup.register(charlie);
// 发送消息
alice.send("大家好,我是Alice!");
System.out.println("---");
bob.send("欢迎Alice加入!");
System.out.println("---");
charlie.send("今天有什么计划吗?");
}
}
运行结果
Alice发送消息:大家好,我是Alice!
Bob收到来自Alice的消息:大家好,我是Alice!
Charlie收到来自Alice的消息:大家好,我是Alice!
---
Bob发送消息:欢迎Alice加入!
Alice收到来自Bob的消息:欢迎Alice加入!
Charlie收到来自Bob的消息:欢迎Alice加入!
---
Charlie发送消息:今天有什么计划吗?
Alice收到来自Charlie的消息:今天有什么计划吗?
Bob收到来自Charlie的消息:今天有什么计划吗?
从结果可见,用户之间完全通过WeChatGroup中介者交互,彼此无需持有对方的引用,实现了彻底解耦。
中介者模式的优缺点
优点
- 降低耦合度:将多对多的复杂关系简化为一对多,避免对象间的直接依赖。
- 集中控制交互:所有交互逻辑集中在中介者中,便于统一管理和维护。
- 简化对象设计:同事对象只需关注自身业务,无需了解其他对象的细节。
- 提高可扩展性:新增同事或修改交互规则时,只需调整中介者即可。
缺点
- 中介者可能过于臃肿:随着业务复杂度增加,中介者可能会集成过多逻辑,变得难以维护(称为 "中介者膨胀")。
- 单点故障风险:所有交互依赖中介者,一旦中介者出现问题,整个系统都会受影响。
- 可能违反开闭原则:如果新增同事类型需要修改中介者逻辑,则违反开闭原则。
适用场景
- 系统中对象之间存在复杂的网状交互关系(如多人协作系统、聊天工具)。
- 一个对象的行为依赖多个其他对象,且这些依赖关系经常变化。
- 希望通过一个中间层封装多个类的交互,避免类之间的直接引用(如 MVC 中的 Controller)。
实际应用案例
- GUI 框架的事件机制:如 Swing 中的
EventDispatcher作为中介者,协调按钮、文本框等组件的事件交互。 - MVC 模式:Controller 作为 View 和 Model 之间的中介者,处理用户输入并更新模型。
- 微服务注册中心:如 Eureka/Nacos,服务之间通过注册中心发现和通信,而非直接交互。
- 消息队列:生产者和消费者通过队列中介通信,无需知道对方的存在。
总结
中介者模式通过引入 "第三方协调者",将对象间的复杂交互集中管理,有效解决了多对象依赖导致的耦合问题。它的核心价值在于解耦—— 将 "蜘蛛网" 式的依赖转化为 "星型" 结构,让系统更清晰、更灵活。
但需注意:中介者模式并非银弹,过度使用可能导致中介者本身成为 "大泥球"。实践中可结合单一职责原则,将复杂中介者拆分为多个小中介者,或通过工厂模式创建中介者,平衡灵活性和可维护性。
合理运用中介者模式,能让你的代码从混乱的依赖中解脱出来,真正实现 "高内聚,低耦合" 的设计目标。