1. 中介者模式:解耦对象交互的利器
中介者模式(Mediator Pattern)是23种经典设计模式中行为型模式的一种,它通过引入一个中介对象来封装一系列对象之间的交互。想象一下机场的塔台控制系统——如果没有塔台调度,所有飞机都需要直接相互通信来确定起降顺序,那将是一场灾难。中介者模式正是为了解决这种"多对多"复杂交互场景而生的。
在实际开发中,当系统出现网状结构依赖时(比如一个聊天室中有多个用户相互发消息),使用中介者模式可以将这些交互关系集中管理。这不仅降低了对象间的耦合度,还使得交互逻辑更容易被理解和修改。作为Java开发者,掌握这个模式能让你在面对复杂交互系统时游刃有余。
2. 模式结构与核心思想
2.1 UML类图解析
中介者模式的标准UML类图包含以下核心角色:
[同事类A] ——> [中介者接口] <—— [同事类B] ^ | [具体中介者实现]- Mediator(抽象中介者):定义同事对象到中介者对象的接口
- ConcreteMediator(具体中介者):实现协调各同事对象的逻辑
- Colleague(同事类):每个同事对象都知道它的中介者对象
2.2 模式运作原理
中介者模式的核心在于"集中控制"。所有同事对象不再直接相互引用,而是通过中介者进行间接通信。当某个同事对象状态改变时,它会通知中介者,由中介者决定如何影响其他同事对象。
这种设计带来了几个显著优势:
- 将网状结构变为星型结构,降低系统复杂度
- 减少子类生成,因为中介者封装了原本分散在各个对象中的行为
- 简化各同事类的实现,使其更专注于自身职责
3. Java代码实现详解
3.1 基础实现示例
让我们通过一个聊天室案例来具体实现中介者模式:
// 抽象中介者 interface ChatMediator { void sendMessage(String msg, User user); void addUser(User user); } // 具体中介者 class ChatMediatorImpl implements ChatMediator { private List<User> users; public ChatMediatorImpl() { this.users = new ArrayList<>(); } @Override public void sendMessage(String msg, User user) { for(User u : this.users) { // 不发送给消息发起者 if(u != user) { u.receive(msg); } } } @Override public void addUser(User user) { this.users.add(user); } } // 抽象同事类 abstract class User { protected ChatMediator mediator; protected String name; public User(ChatMediator med, String name) { this.mediator = med; this.name = name; } public abstract void send(String msg); public abstract void receive(String msg); } // 具体同事类 class UserImpl extends User { public UserImpl(ChatMediator med, String name) { super(med, name); } @Override public void send(String msg) { System.out.println(this.name + " 发送消息: " + msg); mediator.sendMessage(msg, this); } @Override public void receive(String msg) { System.out.println(this.name + " 收到消息: " + msg); } }3.2 客户端使用示例
public class Client { public static void main(String[] args) { ChatMediator mediator = new ChatMediatorImpl(); User user1 = new UserImpl(mediator, "张三"); User user2 = new UserImpl(mediator, "李四"); User user3 = new UserImpl(mediator, "王五"); mediator.addUser(user1); mediator.addUser(user2); mediator.addUser(user3); user1.send("大家好!"); user2.send("欢迎新人!"); } }输出结果:
张三 发送消息: 大家好! 李四 收到消息: 大家好! 王五 收到消息: 大家好! 李四 发送消息: 欢迎新人! 张三 收到消息: 欢迎新人! 王五 收到消息: 欢迎新人!4. 模式应用场景与实战技巧
4.1 典型应用场景
中介者模式特别适用于以下场景:
- 系统中对象之间存在复杂的引用关系,导致系统结构混乱且难以理解
- 想通过中间类来封装多个类中的行为,又不想生成太多子类
- 需要更灵活地控制对象间的交互,而不是硬编码在对象内部
实际开发中的常见应用包括:
- GUI系统中的对话框控件交互
- 消息队列系统中的消息分发
- 游戏开发中的角色交互系统
- 企业应用中的工作流引擎
4.2 实战优化技巧
中介者复杂度控制:当中介者变得过于复杂时,可以考虑将其拆分为多个子中介者,形成分层结构
异步通信实现:对于需要异步处理的场景,可以让中介者维护一个任务队列
class AsyncMediator implements ChatMediator { private ExecutorService executor = Executors.newFixedThreadPool(4); @Override public void sendMessage(String msg, User user) { executor.submit(() -> { // 异步处理消息 for(User u : users) { if(u != user) { u.receive(msg); } } }); } }- 中介者与观察者模式结合:可以使用观察者模式来实现中介者与同事对象之间的通知机制
5. 模式对比与常见误区
5.1 与其他模式的比较
| 模式 | 关注点 | 耦合度 | 适用场景 |
|---|---|---|---|
| 中介者 | 对象间交互 | 低 | 复杂交互系统 |
| 观察者 | 状态变化通知 | 中 | 一对多依赖关系 |
| 外观 | 子系统简化接口 | 低 | 简化复杂子系统 |
5.2 常见实现误区
过度使用中介者:不是所有对象交互都需要中介者,简单的直接引用可能更合适
中介者变成上帝对象:中介者不应知道太多业务逻辑,否则会变得难以维护
忽略线程安全问题:在多线程环境下,中介者需要正确处理并发访问
// 线程安全的中介者实现 class ThreadSafeMediator implements ChatMediator { private final List<User> users = new CopyOnWriteArrayList<>(); @Override public synchronized void addUser(User user) { users.add(user); } @Override public void sendMessage(String msg, User user) { users.stream() .filter(u -> u != user) .forEach(u -> u.receive(msg)); } }6. 性能考量与扩展思考
6.1 性能优化方向
- 消息过滤机制:为中介者添加消息路由功能,避免广播所有消息
interface AdvancedMediator extends ChatMediator { void sendTo(String msg, User sender, String targetType); } class RoleBasedMediator implements AdvancedMediator { private Map<String, List<User>> roleGroups = new HashMap<>(); @Override public void sendTo(String msg, User sender, String targetRole) { roleGroups.getOrDefault(targetRole, Collections.emptyList()) .stream() .filter(u -> u != sender) .forEach(u -> u.receive(msg)); } }- 缓存机制:对于频繁交互的对象,可以缓存部分交互结果
6.2 模式扩展思路
中介者链:类似责任链模式,让多个中介者协同工作
动态中介者:运行时根据条件切换不同的中介者实现
分布式中介者:在微服务架构中,中介者可以作为独立的服务存在
// 分布式中介者的伪代码示例 @RestController class DistributedMediator { @PostMapping("/send") public void sendMessage(@RequestBody MessageDTO message) { // 调用其他服务处理消息 notificationService.notifyUsers(message); } }7. 测试与调试技巧
7.1 单元测试策略
测试中介者模式时,需要关注:
- 中介者是否正确转发消息
- 同事对象是否正确注册到中介者
- 消息过滤和路由逻辑是否正确
class MediatorTest { @Test void testMessageBroadcast() { ChatMediator mediator = new ChatMediatorImpl(); TestUser user1 = new TestUser(mediator, "User1"); TestUser user2 = new TestUser(mediator, "User2"); mediator.addUser(user1); mediator.addUser(user2); user1.send("Hello"); assertEquals("Hello", user2.lastReceivedMessage); } } class TestUser extends User { String lastReceivedMessage; public TestUser(ChatMediator med, String name) { super(med, name); } @Override public void receive(String msg) { this.lastReceivedMessage = msg; } }7.2 调试技巧
- 在中介者中添加日志记录所有交互
- 使用拦截器模式监控消息流
- 可视化中介者的交互拓扑结构
8. 实际项目案例解析
8.1 电商系统中的订单处理
在一个电商系统中,订单创建会触发库存扣减、支付处理、物流通知等多个操作。使用中介者模式可以很好地组织这些交互:
class OrderMediator { private InventoryService inventory; private PaymentService payment; private LogisticsService logistics; public void placeOrder(Order order) { // 检查库存 if(!inventory.checkStock(order)) { throw new RuntimeException("库存不足"); } // 处理支付 PaymentResult result = payment.process(order); if(!result.isSuccess()) { throw new RuntimeException("支付失败"); } // 通知物流 logistics.scheduleDelivery(order); // 更新库存 inventory.updateStock(order); } }8.2 游戏开发中的事件系统
游戏中的角色、道具、场景等对象之间经常需要交互。中介者模式可以管理这些复杂的交互关系:
class GameEventMediator { private Player player; private List<Enemy> enemies; private Environment environment; public void playerAttacked(AttackEvent event) { // 计算伤害 double damage = calculateDamage(event); // 应用伤害 event.getTarget().takeDamage(damage); // 触发环境效果 if(environment.isBloody()) { addBloodEffect(event.getPosition()); } // 通知其他敌人 enemies.stream() .filter(e -> e != event.getTarget()) .forEach(e -> e.onAllyDamaged(event)); } }9. 设计模式组合应用
中介者模式常与其他模式配合使用,形成更强大的解决方案:
9.1 中介者+观察者
// 观察者接口 interface EventListener { void onEvent(String event); } // 观察者模式的中介者 class ObservableMediator { private List<EventListener> listeners = new ArrayList<>(); public void addListener(EventListener listener) { listeners.add(listener); } public void notifyAll(String event) { listeners.forEach(l -> l.onEvent(event)); } }9.2 中介者+命令模式
// 命令接口 interface Command { void execute(); } // 命令模式的中介者 class CommandMediator { private Map<String, Command> commands = new HashMap<>(); public void registerCommand(String name, Command cmd) { commands.put(name, cmd); } public void executeCommand(String name) { Command cmd = commands.get(name); if(cmd != null) { cmd.execute(); } } }10. 代码质量与重构建议
10.1 重构为中介者模式的时机
当发现以下代码异味时,考虑引入中介者模式:
- 类中有大量对其他对象的直接引用
- 修改一个对象需要同时修改多个相关对象
- 对象间的交互逻辑分散在各个类中
10.2 中介者接口设计原则
- 单一职责:一个中介者应该只负责一组相关的交互
- 接口隔离:不要强迫同事类依赖它们不需要的方法
- 依赖倒置:同事类应该依赖抽象中介者,而不是具体实现
// 好的中介者接口设计 interface OrderProcessingMediator { void processOrder(Order order); void cancelOrder(Order order); } // 不好的设计 - 包含不相关方法 interface BadMediator { void processOrder(Order order); void cancelOrder(Order order); void sendMarketingEmail(Customer customer); // 不相关职责 }11. 框架中的中介者模式实现
许多流行框架中都使用了中介者模式的变体:
11.1 Spring框架中的应用
Spring的事件机制本质上是中介者模式的实现:
// 定义事件 class OrderEvent extends ApplicationEvent { public OrderEvent(Object source) { super(source); } } // 事件发布者(同事类) @Service class OrderService { @Autowired private ApplicationEventPublisher publisher; public void placeOrder(Order order) { // 业务逻辑... publisher.publishEvent(new OrderEvent(this)); } } // 事件监听器(同事类) @Component class InventoryListener { @EventListener public void handleOrderEvent(OrderEvent event) { // 处理库存更新 } }11.2 Java Message Service (JMS)
JMS的消息模型也是中介者模式的典型应用:
// 消息生产者 MessageProducer producer = session.createProducer(destination); producer.send(message); // 消息消费者 MessageConsumer consumer = session.createConsumer(destination); consumer.setMessageListener(new MessageListener() { public void onMessage(Message message) { // 处理消息 } });12. 反模式与过度设计警示
虽然中介者模式很强大,但也要警惕以下反模式:
万能中介者:一个中介者类包含所有可能的交互逻辑,变得臃肿难维护
中介者循环依赖:中介者知道所有同事类,同事类又知道中介者,形成双向依赖
性能瓶颈:所有交互都通过单一中介者,可能成为系统瓶颈
避免这些问题的建议:
- 按业务领域划分多个中介者
- 使用接口隔离不同类别的交互
- 考虑异步和非阻塞的实现方式
13. 现代Java中的实现演进
随着Java语言的发展,中介者模式有了更多现代实现方式:
13.1 使用Lambda表达式
class LambdaMediator { private Map<String, Consumer<String>> handlers = new HashMap<>(); public void registerHandler(String eventType, Consumer<String> handler) { handlers.put(eventType, handler); } public void sendEvent(String eventType, String data) { Consumer<String> handler = handlers.get(eventType); if(handler != null) { handler.accept(data); } } }13.2 响应式编程风格
使用Reactive Streams实现中介者:
class ReactiveMediator { private final Map<String, Processor<String, String>> processors = new ConcurrentHashMap<>(); public Flux<String> registerChannel(String channelId) { DirectProcessor<String> processor = DirectProcessor.create(); processors.put(channelId, processor); return processor; } public void sendToChannel(String channelId, String message) { Processor<String, String> processor = processors.get(channelId); if(processor != null) { processor.onNext(message); } } }14. 设计模式在微服务架构中的变体
在微服务架构中,中介者模式演变为以下形态:
- API网关:作为服务间交互的中介者
- 消息代理:如Kafka、RabbitMQ等
- 服务网格:如Istio中的Sidecar代理
这些现代架构组件本质上都是中介者模式在分布式系统中的体现。
15. 中介者模式的替代方案
当中介者模式不适用时,可以考虑:
- 观察者模式:适用于一对多的通知场景
- 责任链模式:适用于需要按顺序处理请求的场景
- 命令模式:适用于需要封装请求为对象的场景
选择依据主要取决于交互的复杂度和变化频率。中介者模式最适合管理复杂的多对多交互关系。