#中介者模式
飞机场里,飞机之间从不直接通信。每一架飞机降落还是起飞,都由塔台统一调度。如果飞机可以直接互相通话,那航线将混乱不堪——每架飞机都需要知道其他所有飞机的位置和状态。
软件开发中,当对象之间的交互关系变得复杂时(如 10 个对象两两互联),引入一个「协调者」来管理对象间的通信,就是中介者模式。
#问题背景:网状结构的复杂度
考虑一个聊天室的场景:用户之间可以直接发消息,但每个用户都需要知道其他所有用户的引用:
public class User {
private String name;
private List<User> friends; // 每个用户持有所有好友引用
public void sendMessage(User to, String message) {
to.receiveMessage(this, message);
}
public void receiveMessage(User from, String message) {
System.out.println(from.getName() + " -> " + this.name + ": " + message);
}
public void broadcast(String message) {
for (User friend : friends) {
friend.receiveMessage(this, message);
}
}
}问题:
- 每个
User持有所有其他User的引用,形成紧密耦合 - 添加新用户时,需要更新所有现有用户的引用
- 用户之间的消息逻辑分散在各个
User类中
flowchart LR
U1[User1] --> U2[User2]
U1 --> U3[User3]
U1 --> U4[User4]
U2 --> U3
U2 --> U4
U3 --> U4如果用中介者模式重构:
flowchart LR
U1[User1] --> M[Mediator\n聊天室]
U2[User2] --> M
U3[User3] --> M
U4[User4] --> M#中介者模式结构
中介者模式(Mediator Pattern)用一个中介对象来封装一系列对象交互。中介者使各个对象不需要显式地相互引用,从而使其耦合松散。
classDiagram
class Mediator {
<<interface>>
+notify(Colleague, String)
}
class ConcreteMediator {
-List~Colleague~ colleagues
+notify(Colleague, String)
}
class Colleague {
<<interface>>
+setMediator(Mediator)
+send(String)
+receive(String)
}
class ConcreteColleagueA {
+send(String)
+receive(String)
}
class ConcreteColleagueB {
+send(String)
+receive(String)
}
Mediator <.. Colleague
Mediator <|.. ConcreteMediator
Colleague <|.. ConcreteColleagueA
Colleague <|.. ConcreteColleagueB
ConcreteMediator o--> Colleague#中介者接口
public interface ChatMediator {
/**
* 发送消息
* @param message 消息内容
* @param from 发送者
*/
void sendMessage(String message, User from);
/**
* 添加用户
*/
void addUser(User user);
}#同事接口
public abstract class User {
protected String name;
protected ChatMediator mediator;
public User(String name, ChatMediator mediator) {
this.name = name;
this.mediator = mediator;
}
public String getName() {
return name;
}
public void setMediator(ChatMediator mediator) {
this.mediator = mediator;
}
public abstract void send(String message);
public abstract void receive(String message);
}#具体同事
public class ChatUser extends User {
public ChatUser(String name, ChatMediator mediator) {
super(name, mediator);
}
@Override
public void send(String message) {
System.out.println(this.name + " 发送消息: " + message);
mediator.sendMessage(message, this);
}
@Override
public void receive(String message) {
System.out.println(this.name + " 收到消息: " + message);
}
}#具体中介者
public class ChatRoom implements ChatMediator {
private final List<User> users = new ArrayList<>();
@Override
public void sendMessage(String message, User from) {
// 广播给所有其他用户
for (User user : users) {
if (user != from) {
user.receive(message);
}
}
}
@Override
public void addUser(User user) {
users.add(user);
}
}#客户端使用
ChatMediator chatRoom = new ChatRoom();
User alice = new ChatUser("Alice", chatRoom);
User bob = new ChatUser("Bob", chatRoom);
User charlie = new ChatUser("Charlie", chatRoom);
chatRoom.addUser(alice);
chatRoom.addUser(bob);
chatRoom.addUser(charlie);
alice.send("大家好!");
// 输出:
// Alice 发送消息: 大家好!
// Bob 收到消息: 大家好!
// Charlie 收到消息: 大家好!#航空调度系统案例
一个更复杂的例子:飞机调度系统。
#参与者
public interface Aircraft {
String getCallsign();
void receive(String msg);
void send(String msg);
}
public class Boeing737 implements Aircraft {
private final String callsign;
private AirTrafficControl controlTower;
public Boeing737(String callsign) {
this.callsign = callsign;
}
public void setControlTower(AirTrafficControl controlTower) {
this.controlTower = controlTower;
}
@Override
public String getCallsign() {
return callsign;
}
@Override
public void receive(String msg) {
System.out.println("[" + callsign + "] 收到: " + msg);
}
@Override
public void send(String msg) {
System.out.println("[" + callsign + "] 发送: " + msg);
controlTower.route(this, msg);
}
}#中介者
public interface AirTrafficControl {
void register(Aircraft aircraft);
void sendMessage(String message, Aircraft from);
void requestLanding(Aircraft aircraft);
void requestTakeoff(Aircraft aircraft);
}
public class ControlTower implements AirTrafficControl {
private final Map<String, Aircraft> aircrafts = new HashMap<>();
private final Queue<Aircraft> landingQueue = new ArrayDeque<>();
private Aircraft currentRunwayOccupant;
@Override
public void register(Aircraft aircraft) {
aircrafts.put(aircraft.getCallsign(), aircraft);
aircraft.setControlTower(this);
broadcast("[" + aircraft.getCallsign() + "] 已注册到塔台");
}
@Override
public void sendMessage(String message, Aircraft from) {
// 广播给其他飞机
for (Aircraft aircraft : aircrafts.values()) {
if (aircraft != from) {
aircraft.receive("[" + from.getCallsign() + "] -> " + message);
}
}
}
@Override
public void requestLanding(Aircraft aircraft) {
if (currentRunwayOccupant != null) {
aircraft.receive("跑道被 [" + currentRunwayOccupant.getCallsign() + "] 占用,等待中");
landingQueue.offer(aircraft);
} else {
currentRunwayOccupant = aircraft;
aircraft.receive("允许降落,跑道已分配");
}
}
@Override
public void requestTakeoff(Aircraft aircraft) {
if (currentRunwayOccupant == aircraft) {
currentRunwayOccupant = null;
broadcast("[" + aircraft.getCallsign() + "] 已起飞");
// 允许下一架飞机降落
if (!landingQueue.isEmpty()) {
Aircraft next = landingQueue.poll();
requestLanding(next);
}
} else {
aircraft.receive("无法起飞,你不在跑道上");
}
}
private void broadcast(String message) {
for (Aircraft aircraft : aircrafts.values()) {
aircraft.receive("[塔台广播] " + message);
}
}
}#调度流程
sequenceDiagram
participant A1 as 飞机A
participant T as 塔台
participant A2 as 飞机B
A1->>T: 请求降落
T->>A1: 允许降落
A2->>T: 请求降落
T->>A2: 等待,跑道占用
A1->>T: 起飞完成
T->>A2: 允许降落#中介者模式 vs 观察者模式
两种模式都可以用于对象间通信,但有不同的应用场景:
| 维度 | 中介者模式 | 观察者模式 |
|---|---|---|
| 通信方式 | 对象间通过中介者通信 | 被观察者直接通知观察者 |
| 耦合度 | 对象只与中介者耦合 | 观察者与被观察者耦合 |
| 关注点 | 协调交互 | 状态变化通知 |
| 典型场景 | UI 组件协调 | 事件监听 |
| 复杂度 | 集中化(中介者复杂) | 分散化(每个对象都可能复杂) |
flowchart LR
subgraph 中介者
A --> M[Mediator]
B --> M
C --> M
M --> A
M --> B
M --> C
end
subgraph 观察者
S[Subject] -->|通知| O1[Observer1]
S -->|通知| O2[Observer2]
end#Spring 中的中介者
#ApplicationEventMulticaster
Spring 的事件广播机制是中介者模式的实现:
flowchart TD
P[ApplicationEventPublisher] --> M[ApplicationEventMulticaster]
M --> L1[ApplicationListener1]
M --> L2[ApplicationListener2]
M --> L3[ApplicationListener3]public interface ApplicationEventPublisher {
void publishEvent(ApplicationEvent event);
}
public interface ApplicationEventMulticaster {
void addApplicationListener(ApplicationListener<?> listener);
void removeApplicationListener(ApplicationListener<?> listener);
void multicastEvent(ApplicationEvent event);
}
// Spring 内置实现
public class SimpleApplicationEventMulticaster
implements ApplicationEventMulticaster {
private final Map<Class<?>, List<ApplicationListener<?>>> listenerMap = new HashMap<>();
@Override
public void multicastEvent(ApplicationEvent event) {
for (ApplicationListener<?> listener : getListeners(event)) {
listener.onApplicationEvent(event);
}
}
}#使用示例
@Component
public class OrderEventMulticaster {
private final ApplicationEventPublisher publisher;
public OrderEventMulticaster(ApplicationEventPublisher publisher) {
this.publisher = publisher;
}
public void publishOrderCreated(Order order) {
publisher.publishEvent(new OrderCreatedEvent(order));
}
}
@Component
public class InventoryService {
@EventListener
public void handleOrderCreated(OrderCreatedEvent event) {
// 扣减库存
inventoryService.reserve(event.getOrder());
}
}
@Component
public class NotificationService {
@EventListener
public void handleOrderCreated(OrderCreatedEvent event) {
// 发送通知
sendConfirmation(event.getOrder());
}
}#中介者模式的优缺点
#优点
- 降低耦合:对象之间不再直接引用
- 集中控制:交互逻辑集中在中介者中
- 简化对象协议:对象不需要知道如何与多个对象交互
- 易于扩展:新增同事只需要修改中介者
#缺点
- 中介者膨胀:交互逻辑复杂时,中介者可能变得非常庞大
- 单点风险:中介者成为系统的中心,如果它崩溃,整个系统受影响
- 隐藏了对象关系:对象间的交互被中介者隐藏,可能导致过度耦合
中介者模式的适用条件
当对象之间的直接引用关系造成紧耦合,且这种耦合关系难以维护时,才考虑使用中介者模式。
如果对象之间的关系本身就不复杂,使用中介者模式反而会增加不必要的复杂度。
#思考题
问题 1:中介者模式和外观模式都封装了子系统,它们有什么区别?
参考答案
| 维度 | 中介者模式 | 外观模式 |
|---|---|---|
| 参与者 | 同级对象(Colleague) | 客户端 + 子系统 |
| 通信方向 | 双向(同事之间通过中介者通信) | 单向(客户端调用外观) |
| 目的 | 解耦对象间的交互 | 简化子系统的使用 |
| 子系统关系 | 子系统组件之间本可直接通信 | 子系统组件之间通常不直接通信 |
| 典型场景 | 聊天室、飞机调度 | 文件系统封装、支付网关封装 |
问题 2:如何在运行时动态配置中介者的行为?
参考答案
几种实现方式:
- 策略模式:中介者持有路由策略
public interface RoutingStrategy {
void route(Message message, Colleague from, List<Colleague> to);
}
public class ChatRoomWithStrategy implements ChatMediator {
private RoutingStrategy strategy;
public void setStrategy(RoutingStrategy strategy) {
this.strategy = strategy;
}
@Override
public void sendMessage(String message, User from) {
strategy.route(new Message(message), from, users);
}
}
// 广播策略、私信策略、群组策略- 配置驱动:通过配置文件定义路由规则
mediator:
rules:
- from: "admin-*"
to: "all"
- from: "vip-*"
to: "vip-*,admin-*"- 规则引擎:使用 Drools 等规则引擎动态配置路由
问题 3:中介者模式在微服务架构中有什么应用?
参考答案
微服务架构中,中介者模式的应用:
- API 网关:作为客户端与微服务的中间层
- 消息代理(RabbitMQ/Kafka):服务间通信的中介
- 服务网格(Istio):Sidecar 代理服务间通信
flowchart LR
Client --> GW[API Gateway]
GW --> S1[Service A]
GW --> S2[Service B]
GW --> S3[Service C]
S1 <--> MB[Message Broker]
S2 <--> MB
S3 <--> MB这些本质上都是分布式中介者的概念。