中介者模式详解及真实场景解决方案

模式定义

中介者模式是一种行为设计模式,通过引入中介对象来封装一组对象之间的交互。该模式将对象间的网状交互转变为星型结构,有效降低对象间的耦合度,并简化系统的维护复杂度。

真实场景案例:飞机交通管制系统

需求背景:

多架飞机需要与塔台通信

交互场景包括:

起飞/降落请求

跑道状态通知

天气预警广播

飞机间避让提醒

需要避免飞机间的直接通信

痛点问题:

飞机对象间存在复杂的网状通信

新增通信协议需要修改所有相关类

紧急情况需要全局广播

通信历史记录需求

解决方案代码实现

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为中介进行交互。

相关推荐
都叫我大帅哥1 小时前
遍历世界的通行证:迭代器模式的导航艺术
java·后端·设计模式
未定义.22112 小时前
UML-银行取款序列图
设计模式·流程图·软件工程·需求分析·uml
程序员沉梦听雨15 小时前
外观模式详解
java·设计模式·外观模式
小马爱打代码16 小时前
设计模式:策略模式 - 消除复杂条件判断的利器
设计模式·策略模式
诺亚凹凸曼17 小时前
23种设计模式-行为型模式-访问者
设计模式
自在如风。17 小时前
Java 设计模式:装饰者模式详解
java·python·设计模式
Pasregret17 小时前
11-Java并发编程终极指南:ThreadLocal与并发设计模式实战
java·开发语言·设计模式
快乐源泉18 小时前
【设计模式】啊?没听过命令模式,有什么优点?
后端·设计模式
快乐源泉20 小时前
【设计模式】已有工厂模式,抽象工厂改进了哪些?
后端·设计模式
快乐源泉20 小时前
【设计模式】什么是工厂模式,有什么优点?
后端·设计模式