中介者模式(Mediator Pattern)
中介者模式是行为型设计模式的一种,其核心思想是通过引入一个 “中介者” 对象,协调多个 “同事” 对象之间的交互,避免同事对象之间直接引用,从而降低系统耦合度。下面将按照你要求的 14 个维度进行全面解析。
定义
中介者模式(Mediator Pattern)定义一个对象,封装一系列对象之间的交互方式,使对象之间无需显式引用,降低耦合度,且可以独立地改变它们之间的交互。
对于中介者模式,你脑海中首先映入的肯定就是中介,我们的生活中到处充满着中介,比如说婚姻介绍所,房产中介,甚至于联合国都是中介。他们的作用都是加强处理人与人之间或者是国与国之间的关系。如果没有这种中介会怎么样呢?就以联合国为例,这世界上有200多个国家,每个国家之间的关系是超级复杂的。
简单来说:用 “第三方”(中介者)代替 “多对多” 的直接交互,将复杂的网状关系转化为 “中介者 - 同事” 的星型关系。
意图
- 减少同事对象之间的直接耦合,避免 “牵一发而动全身” 的修改成本。
- 将多个对象的交互逻辑集中到中介者中,便于统一管理和维护。
- 使同事对象可以独立变化(只需适配中介者接口,无需关心其他同事)。
- 集中相关对象之间复杂的沟通和控制方式。
结构
中介者模式包含 4 个核心角色,各角色职责明确,相互协作完成交互逻辑:
| 角色名称 | 核心职责 |
|---|---|
| 抽象中介者(IMediator) | 定义中介者与同事对象交互的接口,通常包含 “注册同事” 和 “转发消息” 的抽象方法。 |
| 具体中介者(ConcreteMediator) | 实现抽象中介者接口,维护所有同事对象的引用,负责协调同事间的具体交互逻辑。 |
| 抽象同事(IColleague) | 定义同事对象的接口,持有抽象中介者的引用(确保同事能通过中介者通信),包含 “发送消息” 和 “接收消息” 的抽象方法。 |
| 具体同事(ConcreteColleague) | 实现抽象同事接口,当需要与其他同事交互时,不直接调用其他同事,而是通过中介者转发消息。 |
类图(UML)
- Mediator: 中介者,定义一个接口用于与各同事(Colleague)对象通信。
- Colleague: 同事,相关对象

中介者模式的类图需体现 “中介者 - 同事” 的星型依赖关系,具体结构如下:
+-------------------+ +-------------------+
| IMediator |<------| IColleague |
+-------------------+ +-------------------+
| + register(Colleague) | + mediator: IMediator
| + relay(Colleague, msg) | + send(msg: String)
+-------------------+ | + receive(msg: String)
^ +-------------------+
| ^
| |
+-------------------+ +-------------------+ +-------------------+
| ConcreteMediator | | ConcreteColleagueA| | ConcreteColleagueB|
+-------------------+ +-------------------+ +-------------------+
| - colleagues: List<Colleague>| + send(msg) { mediator.relay(this, msg) } | + send(msg) { mediator.relay(this, msg) }
| + register(Colleague) { | + receive(msg) { ... } | + receive(msg) { ... }
| colleagues.add(c) +-------------------+ +-------------------+
| }
| + relay(Colleague, msg) {
| // 逻辑:根据发送者/消息内容,转发给目标同事
| for (c : colleagues) {
| if (c != sender) c.receive(msg);
| }
| }
+-------------------+
核心关系说明:
- 抽象同事(IColleague)持有抽象中介者(IMediator)的引用,确保所有同事都能通过中介者通信。
- 具体中介者(ConcreteMediator)维护所有具体同事的列表,通过
relay方法实现消息转发。
时序图(UML)
时序图用于展示 “同事 A 通过中介者向同事 B 发送消息” 的核心流程,步骤如下:
Client ConcreteColleagueA ConcreteMediator ConcreteColleagueB
| | | |
| 1. 创建中介者 | | |
|------------------->| | |
| | | |
| 2. 创建同事A并注册 | | |
|------------------->| 3. 注册到中介者 | |
| |-------------------->| |
| | | |
| 4. 创建同事B并注册 | | |
|---------------------------------------->| 5. 注册到中介者 |
| | |<-------------------|
| | | |
| 6. 触发同事A发消息 | | |
|------------------->| | |
| | | |
| | 7. 调用中介者转发 | |
| |-------------------->| |
| | | |
| | | 8. 转发消息给同事B |
| | |-------------------->|
| | | |
| | | 9. 同事B接收消息 |
| | |<-------------------|
| | | |
流程解析:
- 客户端先创建具体中介者,再创建同事对象并注册到中介者中。
- 当同事 A 需要发送消息时,调用自身
send方法,内部委托中介者的relay方法。 - 中介者根据逻辑(如 “转发给所有非发送者同事”)将消息传递给同事 B。
- 同事 B 通过
receive方法处理消息,全程不与同事 A 直接交互。
模式分析
中介者模式的核心是 “集中化交互逻辑”,需从以下 3 个角度理解:
(1)交互方式的转变
- 无中介者时:同事对象之间是 “多对多” 网状关系(如 A 需引用 B、C,B 需引用 A、C),耦合度极高。
- 有中介者时:同事对象与中介者是 “一对多” 星型关系(所有同事只引用中介者,中介者引用所有同事),耦合度大幅降低。
(2)中介者的 “控制逻辑”
中介者不仅是 “消息转发器”,还可封装复杂的业务规则,例如:
- 只转发消息给特定同事(而非所有同事)。
- 对消息进行过滤或加工(如格式转换、权限校验)。
- 协调多个同事的交互顺序(如 A 完成操作后,中介者通知 B 执行下一步)。
(3)同事的 “被动性”
同事对象只需关注自身业务逻辑,无需关心 “消息发给谁”“谁会发消息来”:
- 发送消息时:调用
mediator.relay(this, msg)即可,无需知道目标同事。 - 接收消息时:实现
receive方法处理消息,无需知道发送者。
代码实现(Java 版)
下面通过 “聊天室” 场景实现中介者模式:聊天室(中介者)协调多个用户(同事)发送消息,用户发送的消息通过聊天室转发给其他所有用户。
步骤 1:定义抽象中介者(IMediator)
// 抽象中介者:定义注册用户和转发消息的接口
public interface IMediator {
// 注册用户(同事)到中介者
void register(User user);
// 转发消息:参数1=发送者,参数2=消息内容
void relayMessage(User sender, String message);
}
步骤 2:定义抽象同事(User)
// 抽象同事:用户,持有中介者引用
public abstract class User {
protected IMediator mediator; // 持有中介者引用(核心)
protected String name;
public User(IMediator mediator, String name) {
this.mediator = mediator;
this.name = name;
}
// 发送消息(委托给中介者)
public abstract void sendMessage(String message);
// 接收消息(处理消息)
public abstract void receiveMessage(String senderName, String message);
}
步骤 3:实现具体中介者(ChatRoom)
// 具体中介者:聊天室,维护所有用户,负责转发消息
import java.util.ArrayList;
import java.util.List;
public class ChatRoom implements IMediator {
// 维护所有注册的用户(同事)
private final List<User> userList = new ArrayList<>();
@Override
public void register(User user) {
if (!userList.contains(user)) {
userList.add(user);
System.out.println("[聊天室] 用户 " + user.name + " 加入聊天室");
}
}
@Override
public void relayMessage(User sender, String message) {
// 逻辑:将消息转发给所有非发送者的用户
for (User user : userList) {
if (user != sender) { // 不发给自己
user.receiveMessage(sender.name, message);
}
}
}
}
步骤 4:实现具体同事(ConcreteUser)
// 具体同事:普通用户
public class ConcreteUser extends User {
public ConcreteUser(IMediator mediator, String name) {
super(mediator, name);
}
@Override
public void sendMessage(String message) {
System.out.println("[用户 " + name + "] 发送消息:" + message);
// 委托中介者转发消息
mediator.relayMessage(this, message);
}
@Override
public void receiveMessage(String senderName, String message) {
System.out.println("[用户 " + name + "] 收到 " + senderName + " 的消息:" + message);
}
}
步骤 5:客户端测试(Client)
// 客户端:模拟用户在聊天室交互
public class MediatorClient {
public static void main(String[] args) {
// 1. 创建中介者(聊天室)
IMediator chatRoom = new ChatRoom();
// 2. 创建同事(用户)并注册到中介者
User alice = new ConcreteUser(chatRoom, "Alice");
User bob = new ConcreteUser(chatRoom, "Bob");
User charlie = new ConcreteUser(chatRoom, "Charlie");
chatRoom.register(alice);
chatRoom.register(bob);
chatRoom.register(charlie);
// 3. 模拟用户发送消息
System.out.println("\n===== 消息交互开始 =====");
alice.sendMessage("大家好!我是Alice~");
System.out.println("------------------------");
bob.sendMessage("Hi Alice!我是Bob~");
System.out.println("------------------------");
charlie.sendMessage("欢迎加入聊天室!");
}
}
输出结果
[聊天室] 用户 Alice 加入聊天室
[聊天室] 用户 Bob 加入聊天室
[聊天室] 用户 Charlie 加入聊天室
===== 消息交互开始 =====
[用户 Alice] 发送消息:大家好!我是Alice~
[用户 Bob] 收到 Alice 的消息:大家好!我是Alice~
[用户 Charlie] 收到 Alice 的消息:大家好!我是Alice~
------------------------
[用户 Bob] 发送消息:Hi Alice!我是Bob~
[用户 Alice] 收到 Bob 的消息:Hi Alice!我是Bob~
[用户 Charlie] 收到 Bob 的消息:Hi Alice!我是Bob~
------------------------
[用户 Charlie] 发送消息:欢迎加入聊天室!
[用户 Alice] 收到 Charlie 的消息:欢迎加入聊天室!
[用户 Bob] 收到 Charlie 的消息:欢迎加入聊天室!
代码实现2
Alarm(闹钟)、CoffeePot(咖啡壶)、Calendar(日历)、Sprinkler(喷头)是一组相关的对象,在某个对象的事件产生时需要去操作其它对象,形成了下面这种依赖结构:

使用中介者模式可以将复杂的依赖结构变成星形结构:

public abstract class Colleague {
public abstract void onEvent(Mediator mediator);
}
public class Alarm extends Colleague {
@Override
public void onEvent(Mediator mediator) {
mediator.doEvent("alarm");
}
public void doAlarm() {
System.out.println("doAlarm()");
}
}
public class CoffeePot extends Colleague {
@Override
public void onEvent(Mediator mediator) {
mediator.doEvent("coffeePot");
}
public void doCoffeePot() {
System.out.println("doCoffeePot()");
}
}
public class Calender extends Colleague {
@Override
public void onEvent(Mediator mediator) {
mediator.doEvent("calender");
}
public void doCalender() {
System.out.println("doCalender()");
}
}
public class Sprinkler extends Colleague {
@Override
public void onEvent(Mediator mediator) {
mediator.doEvent("sprinkler");
}
public void doSprinkler() {
System.out.println("doSprinkler()");
}
}
public abstract class Mediator {
public abstract void doEvent(String eventType);
}
public class ConcreteMediator extends Mediator {
private Alarm alarm;
private CoffeePot coffeePot;
private Calender calender;
private Sprinkler sprinkler;
public ConcreteMediator(Alarm alarm, CoffeePot coffeePot, Calender calender, Sprinkler sprinkler) {
this.alarm = alarm;
this.coffeePot = coffeePot;
this.calender = calender;
this.sprinkler = sprinkler;
}
@Override
public void doEvent(String eventType) {
switch (eventType) {
case "alarm":
doAlarmEvent();
break;
case "coffeePot":
doCoffeePotEvent();
break;
case "calender":
doCalenderEvent();
break;
default:
doSprinklerEvent();
}
}
public void doAlarmEvent() {
alarm.doAlarm();
coffeePot.doCoffeePot();
calender.doCalender();
sprinkler.doSprinkler();
}
public void doCoffeePotEvent() {
// ...
}
public void doCalenderEvent() {
// ...
}
public void doSprinklerEvent() {
// ...
}
}
public class Client {
public static void main(String[] args) {
Alarm alarm = new Alarm();
CoffeePot coffeePot = new CoffeePot();
Calender calender = new Calender();
Sprinkler sprinkler = new Sprinkler();
Mediator mediator = new ConcreteMediator(alarm, coffeePot, calender, sprinkler);
// 闹钟事件到达,调用中介者就可以操作相关对象
alarm.onEvent(mediator);
}
}
doAlarm()
doCoffeePot()
doCalender()
doSprinkler()
优点
- 降低耦合度:同事对象之间无需直接引用,修改一个同事不会影响其他同事,符合 “开闭原则”。
- 集中化控制:所有交互逻辑集中在中介者中,便于统一维护和扩展(如新增交互规则只需修改中介者)。
- 简化同事代码:同事只需关注自身业务,无需处理复杂的多对象交互逻辑。
- 提高可扩展性:新增同事时,只需实现抽象同事接口并注册到中介者,无需修改现有代码。
缺点
- 中介者可能成为 “上帝类”:当同事数量多、交互逻辑复杂时,中介者的代码会变得臃肿,职责过重,难以维护。
- 中介者与同事的依赖固化:同事必须依赖中介者才能交互,若中介者出现问题,整个系统的交互会受影响。
- 可能违反 “单一职责原则”:中介者可能同时处理消息转发、业务校验、顺序协调等多个职责,职责边界模糊。
适用环境
当系统满足以下条件时,适合使用中介者模式:
- 多个对象之间存在复杂的 “多对多” 交互,导致耦合度极高。
- 希望集中管理对象之间的交互逻辑,避免分散在各个同事中。
- 需简化对象之间的引用关系,使系统结构更清晰(如替换网状关系为星型关系)。
- 需对对象交互进行统一监控、日志记录或权限控制(如中介者中添加日志逻辑)。
模式应用
中介者模式在实际开发中应用广泛,常见场景包括:
- GUI 组件交互:
- 例如:对话框(Dialog)作为中介者,协调按钮(Button)、输入框(Input)、下拉框(Select)的交互(如点击 “提交” 按钮,对话框验证输入框内容,再通知下拉框更新)。
- MVC 架构:
- Controller(控制器)本质是中介者:Model(模型)和 View(视图)不直接交互,Model 数据变化时通过 Controller 通知 View 更新,View 用户操作时通过 Controller 修改 Model。
- 消息队列 / 事件总线:
- 例如:RabbitMQ、EventBus(如 GreenRobot EventBus)作为中介者,发布者(Publisher)和订阅者(Subscriber)通过消息队列交互,无需知道对方存在。
- 分布式系统协调:
- 例如:ZooKeeper 作为中介者,协调分布式服务的注册、发现和配置同步,服务之间无需直接通信。
- 聊天室 / 即时通讯:
- 如前文代码示例,服务器作为中介者,转发用户之间的消息,用户无需知道其他用户的网络地址。
模式扩展
中介者模式可与其他设计模式结合,形成更灵活的解决方案:
(1)与单例模式结合
- 场景:通常系统中只需一个中介者实例(如聊天室服务器、EventBus)。
- 实现:将具体中介者设计为单例(如饿汉式、懒汉式),避免重复创建中介者对象。
(2)与观察者模式结合
- 场景:中介者需感知同事状态变化,或同事需感知中介者的通知。
- 实现:同事作为 “观察者”,中介者作为 “被观察者”;当同事状态变化时,通知中介者(观察者模式反向),中介者再协调其他同事。
(3)与命令模式结合
- 场景:中介者需处理复杂的交互命令(如 “提交订单”“取消订单”)。
- 实现:将不同的交互逻辑封装为命令(Command)对象,中介者通过执行命令来协调同事,降低中介者的职责复杂度。
(4)纯中介者 vs 不纯中介者
- 纯中介者:所有同事交互必须通过中介者,同事之间完全无直接引用(严格解耦)。
- 不纯中介者:允许同事之间在特定场景下直接交互(如简单消息无需中介者转发),平衡解耦和性能。
Android 中的应用
在 Android 开发中,中介者模式的典型应用包括:
(1)Activity 作为 Fragment 的中介者
- 问题:Fragment 之间不能直接通信(若直接
new FragmentB()引用,会导致耦合和生命周期问题)。 - 解决方案:Activity 作为中介者,Fragment 通过 Activity 传递数据或触发操作:
- 定义接口(如
OnFragmentInteractionListener),Activity 实现该接口。 - Fragment 持有接口引用(通过
onAttach方法获取 Activity 实例)。 - Fragment 需通信时,调用接口方法,Activity 在实现中通知其他 Fragment。
- 定义接口(如
// 1. 定义交互接口(中介者接口)
public interface OnFragmentInteractionListener {
void onFragmentADataSent(String data);
}
// 2. Activity作为具体中介者
public class MainActivity extends AppCompatActivity implements OnFragmentInteractionListener {
private FragmentB fragmentB;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
fragmentB = (FragmentB) getSupportFragmentManager().findFragmentById(R.id.fragment_b);
}
// 实现接口,转发FragmentA的数据给FragmentB
@Override
public void onFragmentADataSent(String data) {
if (fragmentB != null) {
fragmentB.updateData(data);
}
}
}
// 3. FragmentA(具体同事)
public class FragmentA extends Fragment {
private OnFragmentInteractionListener listener;
// 绑定Activity时获取中介者引用
@Override
public void onAttach(Context context) {
super.onAttach(context);
if (context instanceof OnFragmentInteractionListener) {
listener = (OnFragmentInteractionListener) context;
} else {
throw new RuntimeException("Activity需实现OnFragmentInteractionListener");
}
}
// 发送数据给FragmentB(通过中介者)
private void sendDataToFragmentB() {
if (listener != null) {
listener.onFragmentADataSent("来自FragmentA的数据");
}
}
}
(2)EventBus/FlowBus
- 原理:EventBus 作为中介者,Activity、Fragment、Service 等组件通过 EventBus 发布(post)和订阅(subscribe)事件,无需直接引用。
- 优势:简化跨组件通信(如 Activity 通知 Service 执行任务,Service 将结果返回给 Activity)。
(3)ViewModel + LiveData(间接中介)
- 场景:Activity/Fragment(View)与 Repository(数据源)不直接交互。
- 原理:ViewModel 作为中介者,View 通过 ViewModel 获取数据,Repository 通过 ViewModel 的 LiveData 通知 View 更新,解耦 View 和数据源。
总结
中介者模式的核心价值是 “解耦多对象交互,集中化控制逻辑”,通过引入中介者,将复杂的网状依赖转化为清晰的星型依赖,使系统更易于维护和扩展。
- 核心记住:中介者模式不是 “消除耦合”,而是 “将分散的耦合集中到中介者中”,用 “中介者与同事的一对多耦合” 替换 “同事间的多对多耦合”。
- 使用建议:避免过度依赖中介者 —— 若同事数量少、交互简单,直接交互可能更高效;只有当交互复杂到影响系统可维护性时,再引入中介者,并注意拆分中介者的职责(避免上帝类)。
通过合理使用中介者模式,可以显著提升系统的灵活性和可扩展性,尤其在复杂交互场景中(如 GUI、分布式系统、组件化开发)。
资料
https://zhuanlan.zhihu.com/p/79488538