为什么需要中介者?
在软件开发中,我们经常会遇到对象之间需要相互通信的场景。当系统规模较小时,对象直接相互引用并通信可能不会带来太大问题。但随着系统复杂度增加,对象间的交互关系会变得错综复杂,形成一个复杂的网状结构。这种高度耦合的设计会导致以下问题:
可维护性差:牵一发而动全身,修改一个对象可能需要修改多个相关对象
复用性低:由于对象间高度依赖,很难单独复用某个对象
扩展困难:新增或修改交互逻辑需要改动大量现有代码
中介者模式正是为解决这些问题而生的。它通过引入一个中介对象来封装对象间的交互,使对象间不再直接引用,而是通过中介者进行间接通信,从而将网状结构转化为星型结构,大大降低了系统的耦合度。
中介者模式的核心概念
模式定义
中介者模式(Mediator Pattern)的定义是:用一个中介对象来封装一系列的对象交互。中介者使各对象不需要显式地相互引用,从而使其耦合松散,而且可以独立地改变它们之间的交互。
模式结构
中介者模式包含四个关键角色:
Mediator(中介者接口):
定义同事对象到中介者对象的接口
通常包含一个或多个事件处理方法
ConcreteMediator(具体中介者):
实现中介者接口
协调各同事对象的行为
知道并维护它的各个同事
Colleague(同事类接口):
定义同事类的接口
通常持有中介者的引用
ConcreteColleague(具体同事类):
实现同事类接口
每个具体同事类只知道自己的行为
需要与其他同事通信时,通过中介者转发
UML类图
┌─────────────┐ ┌─────────────┐
│ Mediator │<------│ Colleague │
└─────────────┘ └─────────────┘^ ^| |
┌─────────────┐ ┌─────────────┐
│ConcreteMedi │ │ConcreteColl │
└─────────────┘ └─────────────┘
深入解析中介者模式
工作原理
对象注册:同事对象在创建时向中介者注册自己
通信机制:当同事对象需要与其他同事通信时,不是直接调用对方的方法,而是通知中介者
消息转发:中介者接收到消息后,根据业务逻辑决定如何转发给其他同事对象
解耦实现:同事对象之间不再相互持有引用,所有交互都通过中介者进行
代码实现详解
让我们通过一个完整的聊天室示例来深入理解中介者模式的实现:
// 1. 定义中介者接口
public interface ChatMediator {void sendMessage(String msg, User user);void addUser(User user);
}// 2. 实现具体中介者
public class ChatMediatorImpl implements ChatMediator {private List<User> users;public ChatMediatorImpl() {this.users = new ArrayList<>();}@Overridepublic void sendMessage(String msg, User user) {for (User u : this.users) {// 消息不发送给发送者自己if (u != user) {u.receive(msg);}}}@Overridepublic void addUser(User user) {this.users.add(user);}
}// 3. 定义同事类(用户)抽象
public 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);
}// 4. 实现具体同事类
public class UserImpl extends User {public UserImpl(ChatMediator med, String name) {super(med, name);}@Overridepublic void send(String msg) {System.out.println(this.name + " 发送消息: " + msg);mediator.sendMessage(msg, this);}@Overridepublic void receive(String msg) {System.out.println(this.name + " 收到消息: " + msg);}
}// 5. 客户端使用
public class ChatClient {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("欢迎新人!");}
}
输出结果
张三 发送消息: 大家好!
李四 收到消息: 大家好!
王五 收到消息: 大家好!
李四 发送消息: 欢迎新人!
张三 收到消息: 欢迎新人!
王五 收到消息: 欢迎新人!
中介者模式的优缺点
优点
降低耦合度:将对象间多对多的关系转化为一对多的关系,减少对象间的直接依赖
集中控制:将交互逻辑集中在中介者中,使交互行为更容易理解和维护
简化对象协议:用中介者和同事间的一对多交互替代了同事之间的多对多交互
提高灵活性:可以独立地改变和复用各个同事类和中介者类
减少子类生成:将原本分布于多个对象间的行为集中在一起,减少子类的生成
缺点
中介者可能变得复杂:随着交互逻辑的增加,中介者可能变得过于庞大和复杂
性能考虑:所有通信都通过中介者转发,可能带来一定的性能开销
单点故障风险:中介者成为系统的关键点,一旦出现问题会影响整个系统
中介者模式的应用场景
中介者模式特别适用于以下场景:
GUI开发:各种UI组件(按钮、文本框等)之间的交互
聊天应用:多个用户之间的消息传递
航空管制系统:飞机与塔台之间的通信协调
事件分发系统:多个对象需要响应同一事件
工作流引擎:协调多个处理节点之间的交互
游戏开发:游戏对象之间的交互管理
实际应用案例
案例1:机场塔台控制系统
在航空领域,飞机之间的通信不是直接进行的,而是通过塔台这个中介者来协调:
// 中介者:塔台
public interface Tower {void registerFlight(Flight flight);void sendWarning(String message, Flight sender);
}// 具体同事:飞机
public abstract class Flight {protected Tower tower;protected String flightNumber;public Flight(Tower tower, String flightNumber) {this.tower = tower;this.flightNumber = flightNumber;tower.registerFlight(this);}public abstract void receiveWarning(String message);public abstract void sendWarning(String message);
}// 使用示例
public class AviationExample {public static void main(String[] args) {Tower tower = new ControlTower();Flight flight1 = new CommercialFlight(tower, "CA123");Flight flight2 = new CargoFlight(tower, "FX456");flight1.sendWarning("前方有气流,请注意");flight2.sendWarning("收到,正在调整高度");}
}
案例2:电子商务订单系统
在电商系统中,订单处理涉及多个组件(库存、支付、物流等),可以使用中介者协调:
public interface OrderMediator {void placeOrder(Order order);void cancelOrder(Order order);void processPayment(Order order);void updateInventory(Order order);void arrangeShipping(Order order);
}public class OrderProcessor implements OrderMediator {// 实现各种订单处理逻辑// 协调库存、支付、物流等子系统
}// 同事类:支付系统
public class PaymentSystem {private OrderMediator mediator;public void processPayment(Order order) {// 处理支付mediator.updateInventory(order);}
}
中介者模式与其他模式的关系
与外观模式:
相似点:都抽象了已有类的功能
区别:外观模式是单向的,为子系统提供统一接口;中介者模式是双向的,协调多个对象间的交互
与观察者模式:
可以组合使用,中介者通常使用观察者模式来实现同事对象之间的通信
观察者模式侧重一对多的依赖关系,中介者模式侧重对象间的交互解耦
与命令模式:
命令模式可用于实现中介者与同事之间的通信机制
与代理模式:
代理模式控制对一个对象的访问,而中介者模式控制多个对象间的交互
最佳实践与注意事项
避免过度使用:不要为了使用模式而使用模式,只有对象间交互确实复杂时才考虑中介者
保持中介者简洁:不要让中介者承担太多职责,必要时可以拆分多个中介者
合理设计接口:中介者接口应该足够抽象,不应依赖于具体同事类
性能优化:对于高频交互的场景,考虑引入缓存或批处理机制
异常处理:中介者应该妥善处理同事对象抛出的异常,避免影响整个系统
总结
中介者模式是一种强大的设计模式,它通过引入中介对象来解耦对象间的复杂交互。在适当的场景下使用中介者模式可以带来以下好处:
使系统结构更加清晰
降低组件间的耦合度
提高代码的可维护性和可扩展性
使交互逻辑更加集中和明确
然而,中介者模式也不是万能的。当交互逻辑简单时,使用中介者可能会引入不必要的复杂性。因此,作为开发者,我们需要根据实际场景权衡利弊,做出最合适的设计决策。