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

发布于:2025-04-11 ⋅ 阅读:(33) ⋅ 点赞:(0)

模式定义

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

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

需求背景:

多架飞机需要与塔台通信
交互场景包括:
起飞/降落请求
跑道状态通知
天气预警广播
飞机间避让提醒
需要避免飞机间的直接通信

痛点问题:

飞机对象间存在复杂的网状通信
新增通信协议需要修改所有相关类
紧急情况需要全局广播
通信历史记录需求

解决方案代码实现

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();
    }
}

真实场景问题解决方案

复杂通信关系管理

// 在中介者中维护飞机列表
private final List<Aircraft> aircrafts = new ArrayList<>();

// 统一消息处理入口
public void sendMessage(AirTrafficMessage message) {
    handleMessage(message);
}

请求队列处理

private final Queue<LandingRequest> landingQueue = new LinkedList<>();

void handleLandingRequest(LandingRequest request) {
    if (!isRunwayAvailable) {
        landingQueue.add(request); // 加入等待队列
    }
}

状态同步机制

private void updateRunwayStatus(RunwayStatus status) {
    isRunwayAvailable = status.content.contains("available");
    // 状态变更后处理队列
}

历史记录追踪

private final List<String> communicationLog = new ArrayList<>();

void logCommunication(String entry) {
    communicationLog.add(new Date() + " - " + entry);
}

典型问题及应对策略

问题场景 解决方案 实现要点
中介者成为性能瓶颈 引入异步消息队列 使用BlockingQueue实现生产消费模式
需要多种通信协议 使用策略模式组合中介者 定义ProtocolHandler接口
中介者单点故障 实现中介者集群 使用ZooKeeper选举主中介者
通信安全性要求高 在中介者中实现加密解密 添加MessageEncryptor组件
需要跨网络通信 将中介者改造为消息代理 使用WebSocket实现远程通信

模式优化技巧

消息优先级处理

// 使用优先队列
private PriorityQueue<AirTrafficMessage> messageQueue = 
    new PriorityQueue<>(Comparator.comparingInt(
        m -> m.getPriority()));

void processMessages() {
    while (!messageQueue.isEmpty()) {
        handleMessage(messageQueue.poll());
    }
}

通信流量控制

// 限流处理
private RateLimiter limiter = RateLimiter.create(10.0); // 10条/秒

public void sendMessage(AirTrafficMessage message) {
    if (limiter.tryAcquire()) {
        handleMessage(message);
    } else {
        // 返回流量控制错误
    }
}

分布式中介者

// 使用消息中间件
class DistributedMediator implements AirTrafficControl {
    private JmsTemplate jmsTemplate;
    
    public void sendMessage(AirTrafficMessage message) {
        jmsTemplate.convertAndSend("ATC_QUEUE", message);
    }
}

消息持久化

// 使用数据库存储重要消息
@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为中介进行交互。


网站公告

今日签到

点亮在社区的每一天
去签到