C++设计模式:中介者模式(聊天室系统)
什么是中介者模式?
中介者模式是一种行为型设计模式,它定义了一个中介者对象,用来封装一组对象之间的交互逻辑,从而使这些对象之间的关系更加松散,减少对象之间的直接依赖。
通俗解释:
- 中介者模式可以类比于一个会议主持人:
在一个会议中,每个与会者不能直接与其他人沟通,而是通过主持人来协调发言和讨论,这样与会者之间的耦合就被移除了,会议流程变得有条理。
在程序中,中介者对象管理并协调多个对象之间的通信,使得对象之间的依赖从直接耦合变为间接耦合。
中介者模式的适用场景
什么时候使用中介者模式?
- 系统中有多个对象需要互相通信,每个对象之间耦合过于复杂。
- 对象之间的交互逻辑不断变化,需要一个集中管理的机制。
- 希望通过一个中心点控制所有对象之间的交互。
例子:
- 聊天室系统:用户之间通过聊天室(中介者)发送消息,而不是直接通信。
- 机场调度系统:各个飞机之间通过调度塔(中介者)通信,避免直接相互协调。
- MVC架构:Controller可以看作是中介者,协调Model和View之间的通信。
中介者模式的结构
UML 类图
+-------------------+
| Mediator | // 中介者接口
+-------------------+
^
|
+-------------------+
| ConcreteMediator | // 具体中介者
+-------------------+
^
|
+-------------------+
| Colleague | // 同事类
+-------------------+
^
|
+-----------------------+
| ConcreteColleagueA | // 具体同事类A
+-----------------------+
| ConcreteColleagueB | // 具体同事类B
+-----------------------+
组成部分:
-
Mediator
(中介者接口)
定义了同事类之间通信的接口。 -
ConcreteMediator
(具体中介者)
实现中介者接口,协调各个同事类之间的交互逻辑。 -
Colleague
(同事类)
定义同事类的通用行为,通过中介者来与其他同事通信。 -
ConcreteColleague
(具体同事类)
实现同事类的具体行为,它们只与中介者通信,而不是直接与其他同事通信。
中介者模式的优缺点
优点:
- 降低耦合性:同事类之间不再直接通信,而是通过中介者进行交互,解耦对象之间的依赖。
- 集中控制交互:交互逻辑集中在中介者中,便于维护和修改。
- 简化对象通信:通过中介者,同事类只需要与中介者打交道,减少了复杂的网状通信。
缺点:
- 中介者复杂性增加:随着同事类数量的增加,中介者的逻辑可能会变得非常复杂。
- 可能导致性能问题:所有通信都通过中介者处理,可能成为性能瓶颈。
案例:聊天室系统
需求描述
我们需要设计一个简单的聊天室系统:
- 多个用户可以加入聊天室。
- 用户发送消息时,消息会通过聊天室转发给其他用户。
- 每个用户只与聊天室通信,而不是直接与其他用户通信。
代码实现
以下是完整的代码实现,输出信息为中文,并配有详细注释。
#include <iostream>
#include <string>
#include <vector>
#include <memory>
// 中介者接口
class Mediator {
public:
virtual void sendMessage(const std::string& message, const std::string& sender) = 0; // 发送消息接口
virtual void addUser(std::shared_ptr<class Colleague> user) = 0; // 添加用户接口
virtual ~Mediator() = default;
};
// 同事类(用户基类)
class Colleague {
public:
std::string name; // 用户名
std::shared_ptr<Mediator> mediator; // 中介者引用
public:
Colleague(const std::string& name, std::shared_ptr<Mediator> mediator)
: name(name), mediator(mediator) {}
virtual void send(const std::string& message) = 0; // 发送消息
virtual void receive(const std::string& message, const std::string& sender) = 0; // 接收消息
virtual ~Colleague() = default;
};
// 具体同事类(用户类)
class User : public Colleague {
public:
User(const std::string& name, std::shared_ptr<Mediator> mediator)
: Colleague(name, mediator) {}
// 发送消息
void send(const std::string& message) override {
std::cout << name << " 发送消息: " << message << std::endl;
mediator->sendMessage(message, name); // 通过中介者发送消息
}
// 接收消息
void receive(const std::string& message, const std::string& sender) override {
std::cout << name << " 收到来自 " << sender << " 的消息: " << message << std::endl;
}
};
// 具体中介者类(聊天室)
class ChatRoom : public Mediator {
private:
std::vector<std::shared_ptr<Colleague>> users; // 聊天室中的用户列表
public:
// 添加用户到聊天室
void addUser(std::shared_ptr<Colleague> user) override {
users.push_back(user);
}
// 发送消息给其他用户
void sendMessage(const std::string& message, const std::string& sender) override {
for (const auto& user : users) {
// 不将消息发给发送者自己
if (user->name != sender) {
user->receive(message, sender);
}
}
}
};
// 客户端代码
int main() {
// 创建聊天室(中介者)
auto chatRoom = std::make_shared<ChatRoom>();
// 创建用户并加入聊天室
auto user1 = std::make_shared<User>("张三", chatRoom);
auto user2 = std::make_shared<User>("李四", chatRoom);
auto user3 = std::make_shared<User>("王五", chatRoom);
chatRoom->addUser(user1);
chatRoom->addUser(user2);
chatRoom->addUser(user3);
// 用户发送消息
user1->send("大家好,我是张三!");
user2->send("你好张三,我是李四!");
user3->send("你好张三和李四,我是王五!");
return 0;
}
运行结果
运行以上代码后,输出如下:
张三 发送消息: 大家好,我是张三!
李四 收到来自 张三 的消息: 大家好,我是张三!
王五 收到来自 张三 的消息: 大家好,我是张三!
李四 发送消息: 你好张三,我是李四!
张三 收到来自 李四 的消息: 你好张三,我是李四!
王五 收到来自 李四 的消息: 你好张三,我是李四!
王五 发送消息: 你好张三和李四,我是王五!
张三 收到来自 王五 的消息: 你好张三和李四,我是王五!
李四 收到来自 王五 的消息: 你好张三和李四,我是王五!
代码讲解
1. 中介者接口
class Mediator {
public:
virtual void sendMessage(const std::string& message, const std::string& sender) = 0;
virtual void addUser(std::shared_ptr<class Colleague> user) = 0;
virtual ~Mediator() = default;
};
- 定义了
sendMessage
和addUser
方法,用于处理消息和用户管理。 Mediator
是中介者的抽象接口,具体中介者需要实现它。
2. 具体中介者类(聊天室)
class ChatRoom : public Mediator {
private:
std::vector<std::shared_ptr<Colleague>> users;
public:
void addUser(std::shared_ptr<Colleague> user) override {
users.push_back(user);
}
void sendMessage(const std::string& message, const std::string& sender) override {
for (const auto& user : users) {
if (user->name != sender) {
user->receive(message, sender);
}
}
}
};
ChatRoom
作为具体的中介者,负责管理用户,并协调消息的发送。- 消息不会发送给消息的发送者自己。
3. 同事类(用户基类)
class Colleague {
public:
std::string name;
std::shared_ptr<Mediator> mediator;
public:
Colleague(const std::string& name, std::shared_ptr<Mediator> mediator)
: name(name), mediator(mediator) {}
virtual void send(const std::string& message) = 0;
virtual void receive(const std::string& message, const std::string& sender) = 0;
virtual ~Colleague() = default;
};
- 定义了
send
和receive
方法,供具体同事类实现。 - 每个同事类持有一个中介者的引用。
4. 具体同事类(用户)
class User : public Colleague {
public:
User(const std::string& name, std::shared_ptr<Mediator> mediator)
: Colleague(name, mediator) {}
void send(const std::string& message) override {
std::cout << name << " 发送消息: " << message << std::endl;
mediator->sendMessage(message, name);
}
void receive(const std::string& message, const std::string& sender) override {
std::cout << name << " 收到来自 " << sender << " 的消息: " << message << std::endl;
}
};
- 用户类通过中介者发送和接收消息,避免了与其他用户的直接交互。
总结
中介者模式的核心优势:
- 降低耦合:各个同事类通过中介者交互,无需直接依赖其他同事类。
- 集中管理交互逻辑:中介者负责协调同事类之间的通信,使得系统的交互逻辑清晰。
适用场景:
- 聊天室系统:用户通过聊天室发送消息。
- 航班调度系统:飞机通过调度塔通信。
- UI组件交互:各组件通过中介者(Controller)协调。
通过本案例,我们清晰地展示了中介者模式如何简化对象之间的交互逻辑,提高代码的灵活性和可维护性!