中介者模式(Mediator Pattern)属于行为型设计模式,它的核心思想是:用一个中介对象来封装一系列对象的交互,使各对象不需要显式地相互引用,从而使其耦合松散,而且可以独立地改变它们之间的交互。想象一个机场塔台的例子:一百架飞机之间不需要直接通信,全部通过塔台协调,塔台就是中介者。如果没有塔台,每架飞机都要和其他所有飞机保持联系,复杂度会以平方级增长。软件系统里也是如此,当多个对象之间存在复杂的网状调用关系时,引入中介者能把这个网状结构压扁成星形结构。

中介者模式的核心结构与原理
中介者模式的角色划分非常清晰,一共四个核心角色。首先是抽象中介者(Mediator),它定义了一个接口用于与各同事对象之间进行通信;其次是具体中介者(ConcreteMediator),它协调各个同事对象实现协作行为;然后是抽象同事类(Colleague),每个同事类都知道自己的中介者对象;最后是具体同事类(ConcreteColleague),负责实现自身的行为,同时通过与中介者通信来完成与其他同事的交互。
理解这个模式的关键在于弄清楚依赖方向的变化。没有中介者时,同事A想通知同事B,就必须持有B的指针或引用,同事之间形成了双向依赖。引入中介者后,所有同事只依赖中介者接口,中介者依赖所有同事,整个系统的耦合被集中到了一处。这其实是把复杂度转移而不是消灭:对象的交互逻辑从分散在各处的直接调用,集中到了中介者这一个类里。这既是优点也是隐患,如果交互逻辑极其庞大,中介者本身可能变成一个上帝类。
下面是标准中介者模式的类骨架代码,先看抽象层面的定义:
#include <iostream>
#include <string>
#include <vector>
#include <memory>
// 前向声明
class Colleague;
// 抽象中介者:定义同事对象通信的接口
class Mediator {
public:
virtual ~Mediator() = default;
virtual void notify(const std::string& event,
Colleague* sender) = 0;
};
// 抽象同事类:持有中介者引用
class Colleague {
protected:
Mediator* mediator_;
std::string name_;
public:
Colleague(Mediator* m, std::string name)
: mediator_(m), name_(std::move(name)) {}
virtual ~Colleague() = default;
virtual void send(const std::string& msg) = 0;
virtual void receive(const std::string& msg) = 0;
const std::string& name() const { return name_; }
};这段代码里有个细节值得注意:Colleague类持有的是Mediator*裸指针,而中介者通常持有同事对象的指针或引用。为什么不用std::shared_ptr?因为中介者和同事之间是双向引用关系,如果双方都用智能指针会形成循环引用,导致内存泄漏。实践中的常见做法是由外部(比如main函数或某个管理器)统一持有同事对象的所有权,中介者内部只保存裸指针做转发。
完整实战:用C++实现一个多人聊天室
聊天室是中介者模式最经典的应用场景。多个用户(同事类)在聊天室(中介者)里发消息,任何一个用户发言,其他所有用户都能收到。用户之间完全不知道彼此的存在,所有消息路由都由聊天室完成。下面是完整可编译的实现:
// 具体同事类:聊天用户
class ChatUser : public Colleague {
public:
using Colleague::Colleague;
void send(const std::string& msg) override {
std::cout << name_ << " 发送: " << msg << std::endl;
// 不直接联系其他用户,而是通知中介者
mediator_->notify(msg, this);
}
void receive(const std::string& msg) override {
std::cout << name_ << " 收到: " << msg << std::endl;
}
};
// 具体中介者:聊天室
class ChatRoom : public Mediator {
private:
std::vector<Colleague*> users_;
public:
void addUser(Colleague* user) {
users_.push_back(user);
}
void notify(const std::string& event,
Colleague* sender) override {
// 广播给除发送者之外的所有人
for (auto* u : users_) {
if (u != sender) {
u->receive(event);
}
}
}
};
int main() {
ChatRoom room; // 中介者由外部创建并掌握生命周期
ChatUser alice(&room, "Alice");
ChatUser bob(&room, "Bob");
ChatUser carol(&room, "Carol");
room.addUser(&alice);
room.addUser(&bob);
room.addUser(&carol);
alice.send("大家好!");
bob.send("你好 Alice");
return 0;
}运行后,Alice发言,Bob和Carol都会收到消息,Bob回复时Alice和Carol也会收到。注意看send方法的实现:用户只是简单地调用mediator_->notify,它根本不关心聊天室里有谁、消息如何路由。假如现在需求变成私聊功能,只需要修改ChatRoom::notify的路由逻辑即可,所有用户类一行代码都不用动。这就是解耦带来的直接好处。
再看生命周期管理。上面代码中用户对象都是栈上的局部变量,聊天室保存的裸指针在作用域内始终有效,这是最安全的写法。如果用户是动态创建的,建议把所有权交给一个std::vector<std::unique_ptr<ChatUser>>管理,聊天室在用户注销时移除指针。切忌让中介者和同事互相用shared_ptr持有对方,循环引用会让引用计数永远无法归零。
中介者模式与观察者模式的区别及适用场景
很多人会把中介者模式和观察者模式搞混,因为两者都涉及对象间的消息传递。区别在于通信方向的结构:观察者模式是一对多的单向广播,_subject状态变化时通知所有观察者,观察者不能反过来影响_subject;而中介者是双向协调,同事既向中介者报告事件,也接收中介者下达的指令,中介者内部可能维护复杂的业务规则。打个比方,观察者模式像公众号推送,中介者模式像电话总机接线员。
另一个实用角度是看交互是否需要应答。如果只是单纯的状态通知,比如数据变化后刷新几个界面,用观察者模式更轻量;如果对象之间存在有来有回的协作流程,比如用户下订单后库存系统要扣减、日志系统要记录、失败时订单要回滚,这种多对象联动配合的场景就适合中介者模式。经典案例还有MVC架构中的控制器、机场调度系统、对话框中各控件之间的联动。
使用中介者模式也要警惕它的代价。第一,交互逻辑全部堆积在中介者里,如果业务复杂,这个类会迅速膨胀,此时可以考虑把中介者拆分成多个职责更单一的协调器。第二,中介者模式只是把耦合从同事之间转移到了同事与中介者之间,系统整体并没有减少耦合,只是让耦合变得可管理。第三,如果对象之间只有两三个固定的交互关系,直接调用反而更简单清晰,硬套模式属于过度设计。判断标准很朴素:当你发现改动一个类需要连带修改一堆相关的类,或者类图上出现了密密麻麻的双向箭头时,就是中介者模式登场的时候。
最后补充一个现代C++的改进思路:如果同事类型固定且数量少,可以用std::function回调替代虚函数接口,减少继承层次;如果需要严格的事件类型区分,可以用枚举或模板参数对notify的事件进行类型化,避免字符串事件名带来的运行时错误。这些变体在游戏引擎的消息总线、GUI框架的事件分发器中都能见到实际应用,理解了中介者模式的基本骨架,再去读这些框架源码会轻松很多。
C++中介者模式设计模式Mediator模式修改时间:2026-09-11 02:34:35