目录
中介者模式(Mediator Pattern)是一种【行为型】设计模式,它通过一个中介对象来封装一系列对象之间的交互,使各对象不需要显式地相互引用,从而降低耦合度,并可以独立地改变它们之间的交互。这种模式将多对多的交互转化为一对多的交互,使系统更易于维护和扩展。
一、模式核心概念与结构
中介者模式包含四个核心角色:
- 抽象中介者(Mediator):定义统一的接口,用于各同事对象之间的通信。
- 具体中介者(Concrete Mediator):实现中介者接口,协调各同事对象的交互逻辑。
- 抽象同事类(Colleague):定义各同事类的公共接口,每个同事类都知道其中介者对象。
- 具体同事类(Concrete Colleague):实现抽象同事类,通过中介者与其他同事通信。
二、C++ 实现示例:聊天室系统
以下是一个简单的聊天室系统示例,演示如何使用中介者模式实现用户之间的通信:
#include <iostream>
#include <string>
#include <memory>
#include <unordered_map>
#include <vector>
// 前向声明
class ChatMediator;
// 抽象同事类:用户
class User {
protected:
std::shared_ptr<ChatMediator> mediator;
std::string name;
public:
User(std::shared_ptr<ChatMediator> m, const std::string& n)
: mediator(m), name(n) {}
virtual ~User() = default;
virtual void send(const std::string& message) = 0;
virtual void receive(const std::string& message, const std::string& sender) = 0;
std::string getName() const { return name; }
};
// 抽象中介者:聊天室
class ChatMediator {
public:
virtual ~ChatMediator() = default;
virtual void addUser(std::shared_ptr<User> user) = 0;
virtual void removeUser(std::shared_ptr<User> user) = 0;
virtual void sendMessage(const std::string& message, const std::string& sender, const std::string& receiver = "") = 0;
};
// 具体同事类:普通用户
class ConcreteUser : public User {
public:
ConcreteUser(std::shared_ptr<ChatMediator> m, const std::string& n)
: User(m, n) {}
void send(const std::string& message) override {
std::cout << name << " sends message: " << message << std::endl;
mediator->sendMessage(message, name);
}
void sendPrivate(const std::string& message, const std::string& receiver) {
std::cout << name << " sends private message to " << receiver << ": " << message << std::endl;
mediator->sendMessage(message, name, receiver);
}
void receive(const std::string& message, const std::string& sender) override {
std::cout << name << " received from " << sender << ": " << message << std::endl;
}
};
// 具体中介者:具体聊天室
class ConcreteChatMediator : public ChatMediator {
private:
std::unordered_map<std::string, std::shared_ptr<User>> users;
public:
void addUser(std::shared_ptr<User> user) override {
users[user->getName()] = user;
std::cout << user->getName() << " joined the chat room" << std::endl;
}
void removeUser(std::shared_ptr<User> user) override {
users.erase(user->getName());
std::cout << user->getName() << " left the chat room" << std::endl;
}
void sendMessage(const std::string& message, const std::string& sender, const std::string& receiver) override {
if (!receiver.empty()) {
// 私聊
auto it = users.find(receiver);
if (it != users.end()) {
it->second->receive(message, sender);
} else {
std::cout << "Error: User " << receiver << " not found" << std::endl;
}
} else {
// 群聊
for (auto& pair : users) {
if (pair.first != sender) { // 不发送给自己
pair.second->receive(message, sender);
}
}
}
}
};
// 客户端代码
int main() {
// 创建聊天室(中介者)
auto chatRoom = std::make_shared<ConcreteChatMediator>();
// 创建用户(同事)
auto alice = std::make_shared<ConcreteUser>(chatRoom, "Alice");
auto bob = std::make_shared<ConcreteUser>(chatRoom, "Bob");
auto charlie = std::make_shared<ConcreteUser>(chatRoom, "Charlie");
// 将用户添加到聊天室
chatRoom->addUser(alice);
chatRoom->addUser(bob);
chatRoom->addUser(charlie);
// 发送群消息
alice->send("Hello, everyone!");
std::cout << "\n";
// 发送私聊消息
bob->sendPrivate("Hi Alice, how are you?", "Alice");
return 0;
}
三、中介者模式的关键特性
- 集中控制交互:
- 中介者封装了对象之间的交互逻辑,使各对象不需要显式引用其他对象。
- 降低耦合度:
- 同事对象之间的依赖关系转移到中介者,减少了对象之间的直接依赖。
- 简化对象协议:
- 将多对多的交互转化为一对多的交互,使协议更清晰简单。
- 提高可维护性:
- 交互逻辑集中在中介者中,便于修改和维护。
四、应用场景
- 对象间通信复杂:
- 当对象之间的交互关系错综复杂,形成网状结构时。
- 例如,GUI 组件之间的交互、多人游戏中的玩家通信。
- 减少子类化:
- 通过中介者封装交互逻辑,可以避免创建大量的子类。
- 复用对象:
- 当对象需要在不同环境中复用时,通过中介者可以解耦其与其他对象的关系。
- 分布式系统:
- 在分布式系统中,中介者可以作为消息代理或服务注册中心。
五、中介者模式与其他设计模式的关系
- 观察者模式:
- 中介者模式可以使用观察者模式实现中介者与同事之间的通信。
- 同事对象可以注册到中介者,当中介者状态变化时通知同事。
- 单例模式:
- 中介者通常是系统中的核心组件,可以使用单例模式确保其唯一性。
- 工厂模式:
- 可以使用工厂模式创建中介者和同事对象,简化对象创建过程。
六、C++ 标准库中的中介者模式应用
- 消息队列:
- 如 Boost.Asio 中的异步消息处理,使用事件循环作为中介者协调各组件。
- 信号与槽机制:
- Qt 框架中的信号与槽机制,信号发送者和接收者通过信号系统(中介者)通信。
- STL 容器与算法:
- STL 容器和算法之间的交互可以看作是一种中介者模式的简化实现。
七、优缺点分析
优点:
- 降低耦合:减少对象之间的直接依赖,提高系统可维护性。
- 集中控制:将交互逻辑集中在中介者中,便于管理和修改。
- 简化协议:使对象之间的协议更简单,易于理解和实现。
- 支持复用:对象可以更容易地在不同环境中复用。
缺点:
- 中介者过载:如果交互逻辑过于复杂,中介者可能变得庞大而难以维护。
- 单点故障:中介者成为系统的核心,一旦出现问题可能影响整个系统。
- 性能问题:中介者可能成为系统的瓶颈,特别是在高并发场景下。
八、实战案例:机场塔台调度系统
以下是一个机场塔台调度系统的实现示例,演示如何使用中介者模式管理飞机起降:
#include <iostream>
#include <string>
#include <memory>
#include <vector>
// 前向声明
class AirportTower;
// 抽象同事类:飞机
class Aircraft {
protected:
std::shared_ptr<AirportTower> tower;
std::string flightNumber;
public:
Aircraft(std::shared_ptr<AirportTower> t, const std::string& flight)
: tower(t), flightNumber(flight) {}
virtual ~Aircraft() = default;
virtual void requestLanding() = 0;
virtual void requestTakeoff() = 0;
virtual void receiveClearance(const std::string& message) = 0;
std::string getFlightNumber() const { return flightNumber; }
};
// 抽象中介者:机场塔台
class AirportTower {
public:
virtual ~AirportTower() = default;
virtual void registerAircraft(std::shared_ptr<Aircraft> aircraft) = 0;
virtual void handleLandingRequest(std::shared_ptr<Aircraft> aircraft) = 0;
virtual void handleTakeoffRequest(std::shared_ptr<Aircraft> aircraft) = 0;
virtual void sendClearance(const std::string& message, std::shared_ptr<Aircraft> aircraft) = 0;
};
// 具体同事类:客机
class PassengerAircraft : public Aircraft {
public:
PassengerAircraft(std::shared_ptr<AirportTower> t, const std::string& flight)
: Aircraft(t, flight) {}
void requestLanding() override {
std::cout << flightNumber << " requests landing" << std::endl;
tower->handleLandingRequest(shared_from_this());
}
void requestTakeoff() override {
std::cout << flightNumber << " requests takeoff" << std::endl;
tower->handleTakeoffRequest(shared_from_this());
}
void receiveClearance(const std::string& message) override {
std::cout << flightNumber << " received clearance: " << message << std::endl;
}
};
// 具体中介者:国际机场塔台
class InternationalAirportTower : public AirportTower {
private:
std::vector<std::shared_ptr<Aircraft>> aircrafts;
bool runwayAvailable;
public:
InternationalAirportTower() : runwayAvailable(true) {}
void registerAircraft(std::shared_ptr<Aircraft> aircraft) override {
aircrafts.push_back(aircraft);
std::cout << aircraft->getFlightNumber() << " registered with tower" << std::endl;
}
void handleLandingRequest(std::shared_ptr<Aircraft> aircraft) override {
if (runwayAvailable) {
runwayAvailable = false;
sendClearance("Runway clear for landing", aircraft);
} else {
sendClearance("Wait for landing clearance", aircraft);
}
}
void handleTakeoffRequest(std::shared_ptr<Aircraft> aircraft) override {
if (runwayAvailable) {
runwayAvailable = false;
sendClearance("Runway clear for takeoff", aircraft);
} else {
sendClearance("Wait for takeoff clearance", aircraft);
}
}
void sendClearance(const std::string& message, std::shared_ptr<Aircraft> aircraft) override {
aircraft->receiveClearance(message);
// 模拟操作完成,释放跑道
if (message.find("clear") != std::string::npos) {
runwayAvailable = true;
std::cout << "Runway is now available" << std::endl;
}
}
};
// 客户端代码
int main() {
// 创建机场塔台(中介者)
auto tower = std::make_shared<InternationalAirportTower>();
// 创建飞机(同事)
auto flight1 = std::make_shared<PassengerAircraft>(tower, "CA1234");
auto flight2 = std::make_shared<PassengerAircraft>(tower, "MU5678");
// 注册飞机到塔台
tower->registerAircraft(flight1);
tower->registerAircraft(flight2);
// 飞机请求操作
flight1->requestLanding();
flight2->requestTakeoff();
return 0;
}
九、实现注意事项
- 避免中介者过度复杂:
- 中介者应专注于协调对象间的交互,避免承担过多业务逻辑。
- 松耦合设计:
- 中介者和同事对象之间应保持松耦合,通过抽象接口通信。
- 中介者生命周期管理:
- 确保中介者的生命周期覆盖所有同事对象的生命周期。
- 线程安全:
- 在多线程环境中,中介者的操作可能需要同步机制(如互斥锁)。
中介者模式是 C++ 中处理对象间复杂交互的重要工具,通过引入中介者对象,可以将网状的对象关系转化为星型结构,降低系统耦合度,提高可维护性和可扩展性。