中介者模式:集中对象交互逻辑
FreeGuideOnline
最新
2026-06-18
中介者模式:集中对象交互逻辑
在软件系统中,当多个对象之间相互引用、彼此通信时,对象间的耦合会变得错综复杂,形成一张难以维护的“网状结构”。中介者模式(Mediator Pattern)正是为了化解这种混乱而生,它引入一个中介者对象,将所有对象之间的交互逻辑集中管理,使对象之间不再直接显式引用,而是通过中介者间接沟通。
1. 模式概述
意图:用一个中介对象来封装一系列对象之间的交互,使各对象无需显式地相互引用,从而使其耦合松散,并可以独立地改变它们之间的交互。
核心思想:将对象间的“多对多”关系转化为“一对多”关系。原本需要互相通信的同事对象,只认识中介者,所有消息都经由中介者转发,交互逻辑从中剥离出来,集中存放在中介者内部。
现实类比:
- 机场塔台:飞机之间不会直接通信来协调起降,而是通过塔台(中介者)统一调度。
- 聊天室:用户不直接给其他用户发消息,而是把消息发送到聊天室(中介者),由后者广播给所有人或特定人。
2. 模式结构
中介者模式通常包含以下几种角色:
| 角色 | 说明 |
|---|---|
| Mediator(抽象中介者) | 定义同事对象之间通信的接口,通常包含一个或多个通信方法。 |
| ConcreteMediator(具体中介者) | 实现中介者接口,维护一个对各个同事对象的引用,负责协调它们之间的交互,封装具体的业务逻辑。 |
| Colleague(抽象同事类) | 定义同事对象的接口,持有对中介者的引用,通过该引用与其他同事通信。 |
| ConcreteColleague(具体同事类) | 具体的同事对象,实现自己的业务方法,需要与其他同事通信时,触发中介者的相应方法。 |
结构图示意(文字描述):
Mediator (interface)
|
|----- ConcreteMediator
|
|
ColleagueA ---> Mediator
ColleagueB ---> Mediator
- 每一个
Colleague内部都维护一个Mediator引用。 ConcreteMediator内部持有所有Colleague的引用,根据需要调用它们的方法。- 同事之间互不直接持有引用,所有交互请求都提交给中介者。
3. 代码示例(Java)
以下用例模拟一个简易的智能家居系统:传感器(Sensor)检测到环境变化后,需要通过控制中心(Mediator)通知报警器(Alarm)和显示器(Display)。
3.1 定义抽象中介者
// 抽象中介者
interface SmartHomeMediator {
void register(Device device);
void eventOccurred(String eventType, Device device);
}
// 抽象同事类
abstract class Device {
protected SmartHomeMediator mediator;
protected String name;
public Device(SmartHomeMediator mediator, String name) {
this.mediator = mediator;
this.name = name;
mediator.register(this);
}
public abstract void sendEvent(String event);
public abstract void receiveEvent(String event);
}
3.2 定义具体同事类
class Sensor extends Device {
public Sensor(SmartHomeMediator mediator, String name) {
super(mediator, name);
}
public void detectMotion() {
System.out.println(name + "检测到移动!");
sendEvent("motion_detected");
}
@Override
public void sendEvent(String event) {
mediator.eventOccurred(event, this);
}
@Override
public void receiveEvent(String event) {
// 传感器一般不需要接收事件,但保留方法以保持统一接口
}
}
class Alarm extends Device {
public Alarm(SmartHomeMediator mediator, String name) {
super(mediator, name);
}
@Override
public void sendEvent(String event) {
mediator.eventOccurred(event, this);
}
@Override
public void receiveEvent(String event) {
if (event.equals("motion_detected")) {
System.out.println(name + ":发出警报声!");
}
}
}
class Display extends Device {
public Display(SmartHomeMediator mediator, String name) {
super(mediator, name);
}
@Override
public void sendEvent(String event) {
mediator.eventOccurred(event, this);
}
@Override
public void receiveEvent(String event) {
if (event.equals("motion_detected")) {
System.out.println(name + ":显示“有人闯入”");
}
}
}
3.3 实现具体中介者
class ConcreteSmartHomeMediator implements SmartHomeMediator {
private Sensor sensor;
private Alarm alarm;
private Display display;
@Override
public void register(Device device) {
if (device instanceof Sensor) {
this.sensor = (Sensor) device;
} else if (device instanceof Alarm) {
this.alarm = (Alarm) device;
} else if (device instanceof Display) {
this.display = (Display) device;
}
}
@Override
public void eventOccurred(String eventType, Device device) {
if (eventType.equals("motion_detected") && device instanceof Sensor) {
if (alarm != null) {
alarm.receiveEvent(eventType);
}
if (display != null) {
display.receiveEvent(eventType);
}
}
}
}
3.4 客户端调用
public class Client {
public static void main(String[] args) {
ConcreteSmartHomeMediator mediator = new ConcreteSmartHomeMediator();
Sensor sensor = new Sensor(mediator, "门口红外传感器");
Alarm alarm = new Alarm(mediator, "客厅警铃");
Display display = new Display(mediator, "中控显示屏");
sensor.detectMotion();
}
}
运行结果:
门口红外传感器检测到移动!
客厅警铃:发出警报声!
中控显示屏:显示“有人闯入”
通过中介者,Sensor 无需直接依赖 Alarm 或 Display,所有协调逻辑集中在 ConcreteSmartHomeMediator 中,添加新设备(如手机推送)时只需修改中介者即可。
4. 中介者模式的优缺点
✅ 优点
- 降低耦合度:各个同事对象之间解耦,它们只依赖于抽象中介者,可以独立变化和复用。
- 集中控制交互逻辑:所有交互关系集中在一个中介者里,符合“单一职责原则”,便于理解、维护和修改。
- 减少子类生成:无需为每一组对象交互创建新的协作类,中介者可以动态组合对象的交互行为。
- 简化对象协议:用一对多的中介者交互替代多对多的网状交互,更容易理解。
❌ 缺点
- 中介者可能变得庞大复杂:随着同事对象增多和交互逻辑复杂化,具体中介者可能会变成一个难以维护的“上帝类”。
- 中介者成为瓶颈:如果中介者出现问题,整个系统的通信将瘫痪。
- 同事类依然需要通信:虽然同事之间解耦,但它们仍需要知道中介者的存在,并未完全消除耦合。
5. 适用场景
- 一组对象以定义良好但复杂的方式进行通信,相互依赖关系混乱且难以理解。
- 一个对象引用了多个其他对象,并且直接与这些对象通信,导致该对象难以复用。
- 想定制一个分布在多个类中的行为,而又不想生成太多子类。
- 在 GUI 开发中,经常使用中介者模式来协调多个 UI 组件之间的交互(如对话框中的按钮、复选框、文本框的联动)。
- 在聊天室、消息中间件、微服务中的消息代理等典型场景中,可见中介者模式的实际应用。
6. 与其他模式的关系
| 模式 | 关系 |
|---|---|
| 观察者模式 | 中介者可以通过观察者模式来实现与各同事之间的通信。同事类可以充当观察者,中介者充当目标,当事件发生时通知所有订阅该事件的同事。 |
| 外观模式 | 外观模式为子系统提供统一接口,但子系统内部仍可直接交互;中介者则禁止子系统组件直接交互,所有通信必须通过中介者。 |
| 命令模式 | 发送请求时可以使用命令对象封装请求并传递给中介者,中介者根据请求类型进行调度,实现更灵活的逻辑解耦。 |
7. 实现要点与最佳实践
- 接口设计:抽象中介者应定义同事之间共通的通信接口,保持方法通用。可以由具体中介者决定如何分发事件。
- 避免中介者职责过重:当具体中介者过于庞大时,考虑将部分交互逻辑拆分到其他辅助类中,或者使用多个中介者分工协作(例如引入“中介者链”)。
- 使用事件类型枚举:传递事件时尽量使用明确的类型(如枚举),避免字符串硬编码,提高代码可维护性。
- 双向通信:同事类既可以发送事件给中介者,也可以从中介者接收事件,设计时注意区分通知方法与业务方法。
- 同事类的注册:可以在构造函数中由同事对象自行注册到中介者,也可以由中介者主动管理同事列表,根据实际情况选择。
8. 总结
中介者模式通过将对象间的网状交互星状化,有效降低了系统的耦合度,使交互逻辑清晰集中。它适合于对象群复杂通信的场景,但需警惕“上帝中介者”的出现。正确使用该模式,可以让代码结构更简洁、更易于扩展和维护,是面向对象设计中应对复杂交互关系的利器。