模式定义
中介者模式是一种行为设计模式,通过引入中介对象来封装一组对象之间的交互。该模式将对象间的网状交互转变为星型结构,有效降低对象间的耦合度,并简化系统的维护复杂度。
真实场景案例:飞机交通管制系统
需求背景:
多架飞机需要与塔台通信
交互场景包括:
起飞/降落请求
跑道状态通知
天气预警广播
飞机间避让提醒
需要避免飞机间的直接通信
痛点问题:
飞机对象间存在复杂的网状通信
新增通信协议需要修改所有相关类
紧急情况需要全局广播
通信历史记录需求
解决方案代码实现
java
import java.util.*;
// 通信消息基类
abstract class AirTrafficMessage {
protected String sender;
protected String content;
protected Date timestamp = new Date();
public AirTrafficMessage(String sender, String content) {
this.sender = sender;
this.content = content;
}
public abstract String getMessageType();
}
// 具体消息类型
class LandingRequest extends AirTrafficMessage {
public LandingRequest(String sender) {
super(sender, "Request landing clearance");
}
@Override
public String getMessageType() {
return "LANDING_REQUEST";
}
}
class RunwayStatus extends AirTrafficMessage {
public RunwayStatus(String sender, boolean isAvailable) {
super(sender, "Runway " + (isAvailable ? "available" : "occupied"));
}
@Override
public String getMessageType() {
return "RUNWAY_STATUS";
}
}
// 中介者接口
interface AirTrafficControl {
void registerAircraft(Aircraft aircraft);
void sendMessage(AirTrafficMessage message);
void broadcastEmergency(String emergencyInfo);
}
// 具体中介者(塔台)
class ControlTower implements AirTrafficControl {
private final List<Aircraft> aircrafts = new ArrayList<>();
private final Queue<LandingRequest> landingQueue = new LinkedList<>();
private boolean isRunwayAvailable = true;
private final List<String> communicationLog = new ArrayList<>();
@Override
public void registerAircraft(Aircraft aircraft) {
aircrafts.add(aircraft);
logCommunication(aircraft.getCallSign() + " registered");
}
@Override
public void sendMessage(AirTrafficMessage message) {
handleMessage(message);
logCommunication(message.sender + " [" +
message.getMessageType() + "]: " + message.content);
}
private void handleMessage(AirTrafficMessage message) {
switch (message.getMessageType()) {
case "LANDING_REQUEST":
handleLandingRequest((LandingRequest) message);
break;
case "RUNWAY_STATUS":
updateRunwayStatus((RunwayStatus) message);
break;
}
}
private void handleLandingRequest(LandingRequest request) {
if (isRunwayAvailable) {
notifyAircraft(request.sender, "Cleared to land");
isRunwayAvailable = false;
} else {
landingQueue.add(request);
notifyAircraft(request.sender,
"Holding pattern. Position in queue: " + landingQueue.size());
}
}
private void updateRunwayStatus(RunwayStatus status) {
isRunwayAvailable = status.content.contains("available");
if (isRunwayAvailable && !landingQueue.isEmpty()) {
LandingRequest next = landingQueue.poll();
notifyAircraft(next.sender, "Cleared to land");
isRunwayAvailable = false;
}
}
@Override
public void broadcastEmergency(String emergencyInfo) {
aircrafts.forEach(aircraft ->
aircraft.receiveBroadcast("EMERGENCY: " + emergencyInfo));
logCommunication("EMERGENCY BROADCAST: " + emergencyInfo);
}
private void logCommunication(String entry) {
communicationLog.add(new Date() + " - " + entry);
}
public void printCommunicationLog() {
System.out.println("\n=== Communication Log ===");
communicationLog.forEach(System.out::println);
}
}
// 同事类(飞机)
class Aircraft {
private final String callSign;
private final AirTrafficControl controlTower;
public Aircraft(String callSign, AirTrafficControl controlTower) {
this.callSign = callSign;
this.controlTower = controlTower;
controlTower.registerAircraft(this);
}
public String getCallSign() {
return callSign;
}
public void requestLanding() {
controlTower.sendMessage(new LandingRequest(callSign));
}
public void reportRunwayStatus(boolean isAvailable) {
controlTower.sendMessage(new RunwayStatus(callSign, isAvailable));
}
public void receiveBroadcast(String message) {
System.out.println(callSign + " received: " + message);
}
}
// 使用示例
public class MediatorPatternExample {
public static void main(String[] args) {
AirTrafficControl tower = new ControlTower();
Aircraft flight123 = new Aircraft("FL123", tower);
Aircraft flight456 = new Aircraft("FL456", tower);
Aircraft flight789 = new Aircraft("FL789", tower);
// 发送降落请求
flight123.requestLanding();
flight456.requestLanding();
// 报告跑道状态
flight123.reportRunwayStatus(false); // 占用跑道
flight123.reportRunwayStatus(true); // 释放跑道
// 紧急广播
tower.broadcastEmergency("Severe weather approaching");
// 查看通信记录
((ControlTower) tower).printCommunicationLog();
}
}
真实场景问题解决方案
复杂通信关系管理
java
// 在中介者中维护飞机列表
private final List<Aircraft> aircrafts = new ArrayList<>();
// 统一消息处理入口
public void sendMessage(AirTrafficMessage message) {
handleMessage(message);
}
请求队列处理
java
private final Queue<LandingRequest> landingQueue = new LinkedList<>();
void handleLandingRequest(LandingRequest request) {
if (!isRunwayAvailable) {
landingQueue.add(request); // 加入等待队列
}
}
状态同步机制
java
private void updateRunwayStatus(RunwayStatus status) {
isRunwayAvailable = status.content.contains("available");
// 状态变更后处理队列
}
历史记录追踪
java
private final List<String> communicationLog = new ArrayList<>();
void logCommunication(String entry) {
communicationLog.add(new Date() + " - " + entry);
}
典型问题及应对策略
问题场景 | 解决方案 | 实现要点 |
---|---|---|
中介者成为性能瓶颈 | 引入异步消息队列 | 使用BlockingQueue实现生产消费模式 |
需要多种通信协议 | 使用策略模式组合中介者 | 定义ProtocolHandler接口 |
中介者单点故障 | 实现中介者集群 | 使用ZooKeeper选举主中介者 |
通信安全性要求高 | 在中介者中实现加密解密 | 添加MessageEncryptor组件 |
需要跨网络通信 | 将中介者改造为消息代理 | 使用WebSocket实现远程通信 |
模式优化技巧
消息优先级处理
java
// 使用优先队列
private PriorityQueue<AirTrafficMessage> messageQueue =
new PriorityQueue<>(Comparator.comparingInt(
m -> m.getPriority()));
void processMessages() {
while (!messageQueue.isEmpty()) {
handleMessage(messageQueue.poll());
}
}
通信流量控制
java
// 限流处理
private RateLimiter limiter = RateLimiter.create(10.0); // 10条/秒
public void sendMessage(AirTrafficMessage message) {
if (limiter.tryAcquire()) {
handleMessage(message);
} else {
// 返回流量控制错误
}
}
分布式中介者
java
// 使用消息中间件
class DistributedMediator implements AirTrafficControl {
private JmsTemplate jmsTemplate;
public void sendMessage(AirTrafficMessage message) {
jmsTemplate.convertAndSend("ATC_QUEUE", message);
}
}
消息持久化
java
// 使用数据库存储重要消息
@Entity
class PersistentMessage {
@Id
private Long id;
private String content;
private Date timestamp;
}
void logCommunication(String entry) {
messageRepository.save(new PersistentMessage(entry));
}
模式优缺点分析
优点:
将对象间耦合度从O(n²)降低到O(n)
简化同事类的实现
集中控制交互逻辑
易于扩展新的交互方式
缺点:
中介者可能变得过于复杂
可能成为系统性能瓶颈
增加了间接调用层级
适用场景总结
对象间存在复杂的网状引用关系
需要集中控制多个组件的交互
需要维护交互历史记录
系统需要支持不同交互协议
需要实现跨网络的分布式通信
在中型以上系统中使用中介者模式,通常可以降低30%-50%的组件间耦合度。该模式特别适用于航空管制系统、聊天应用、分布式系统协调器等场景。当系统需要从单体架构向微服务架构演进时,中介者模式可以作为重要的过渡设计方案。
一句话总结
中介者模式是使用中介类将双方服务的实现进行交互,是双方服务的协调者,双方服务感知到的都是中介服务,比如rocketmq种的消费者,生产者以broker为中介进行交互。