中介者设计模式的核心思想是将多个对象之间的复杂交互逻辑封装到一个中介者对象中,各个对象不再直接相互引用,而是通过中介者来传递消息和协调操作,从而降低对象之间的耦合度,让系统更容易维护和扩展。

中介者设计模式的核心角色
在C++实现中介者模式时,通常会包含以下几个核心角色:
- 中介者接口(Mediator):定义各个同事对象之间通信的接口,通常包含用于发送消息或者协调操作的方法。
- 具体中介者(ConcreteMediator):实现中介者接口,维护各个同事对象的引用,负责处理各个同事对象之间的交互逻辑。
- 同事类接口(Colleague):定义同事对象的通用接口,通常包含一个指向中介者的引用,用于和中介者通信。
- 具体同事类(ConcreteColleague):实现同事类接口,每个具体同事类只知道自己的业务逻辑,需要和其他同事交互时,会通过持有的中介者对象来传递消息。
实现步骤与示例代码
下面以一个简单的聊天室场景为例,实现中介者设计模式。在聊天室中,每个用户是同事对象,聊天室是中介者,用户发送消息时不需要直接知道其他用户的存在,只需要把消息发给聊天室,由聊天室转发给所有其他用户。
1. 定义中介者接口
首先定义聊天室的中介者接口,声明转发消息的方法:
// 前置声明同事类
class Colleague;
// 中介者接口
class Mediator {
public:
virtual ~Mediator() = default;
// 转发消息的方法,sender是发送消息的同事,msg是消息内容
virtual void forward_message(Colleague* sender, const std::string& msg) = 0;
// 注册同事对象到中介者
virtual void register_colleague(Colleague* colleague) = 0;
};
2. 定义同事类接口
同事类接口中需要持有中介者的引用,用于发送消息:
class Colleague {
protected:
Mediator* mediator; // 持有中介者指针
std::string name; // 同事名称,这里对应聊天用户昵称
public:
Colleague(Mediator* med, const std::string& n) : mediator(med), name(n) {}
virtual ~Colleague() = default;
// 发送消息的方法,调用中介者的转发接口
void send_message(const std::string& msg) {
if (mediator != nullptr) {
mediator->forward_message(this, msg);
}
}
// 接收消息的方法,由中介者调用
virtual void receive_message(const std::string& msg, const std::string& sender_name) = 0;
// 获取同事名称
std::string get_name() const {
return name;
}
};
3. 实现具体中介者
具体中介者维护所有注册的同事对象,实现消息转发逻辑:
#include <vector>
#include <algorithm>
#include <iostream>
class ChatRoomMediator : public Mediator {
private:
std::vector<Colleague*> colleagues; // 存储所有注册的同事对象
public:
void register_colleague(Colleague* colleague) override {
colleagues.push_back(colleague);
}
void forward_message(Colleague* sender, const std::string& msg) override {
// 遍历所有同事,除了发送者之外,都转发消息
for (Colleague* colleague : colleagues) {
if (colleague != sender) {
colleague->receive_message(msg, sender->get_name());
}
}
}
};
4. 实现具体同事类
具体同事类实现接收消息的逻辑:
class ChatUser : public Colleague {
public:
ChatUser(Mediator* med, const std::string& n) : Colleague(med, n) {
// 创建用户时自动注册到中介者
if (med != nullptr) {
med->register_colleague(this);
}
}
void receive_message(const std::string& msg, const std::string& sender_name) override {
std::cout << name << " 收到来自 " << sender_name << " 的消息:" << msg << std::endl;
}
};
5. 测试代码
最后编写测试代码,验证中介者模式的实现效果:
int main() {
// 创建聊天室中介者
ChatRoomMediator chat_room;
// 创建三个聊天用户,自动注册到聊天室
ChatUser user1(&chat_room, "张三");
ChatUser user2(&chat_room, "李四");
ChatUser user3(&chat_room, "王五");
// 用户1发送消息
std::cout << "张三发送消息:" << std::endl;
user1.send_message("大家好,我是张三");
std::cout << std::endl;
// 用户2发送消息
std::cout << "李四发送消息:" << std::endl;
user2.send_message("我是李四,很高兴认识大家");
return 0;
}
运行上述代码后,输出结果如下:
张三发送消息: 李四 收到来自 张三 的消息:大家好,我是张三 王五 收到来自 张三 的消息:大家好,我是张三 李四发送消息: 张三 收到来自 李四 的消息:我是李四,很高兴认识大家 王五 收到来自 李四 的消息:我是李四,很高兴认识大家
实现注意事项
在C++中实现中介者模式时,需要注意以下几点:
- 中介者对象需要管理所有同事对象的生命周期吗?通常不建议中介者负责同事对象的生命周期,同事对象的创建和销毁由外部逻辑控制,中介者只持有同事的指针或者弱引用,避免出现循环引用导致内存泄漏。
- 如果同事对象数量很多,中介者的转发逻辑可能会变得复杂,这时候可以考虑将中介者的逻辑拆分,或者根据业务场景优化转发规则,避免中介者变成臃肿的万能类。
- 同事类和中介者之间的依赖是单向的,同事类依赖中介者,但是中介者不应该依赖具体同事类的实现,而是通过同事类的通用接口来操作,这样才能保证模式的灵活性。
适用场景
中介者设计模式适合用在以下场景:
- 系统中多个对象之间存在复杂的交互关系,导致对象之间的耦合度很高,修改一个对象会影响多个其他对象。
- 想要复用某个对象,但是该对象和其他很多对象存在依赖,直接复用很困难。
- 需要封装多个对象之间的交互行为,让这些交互逻辑可以独立变化,不影响各个对象本身的业务逻辑。