中介者模式(Mediator Pattern)是一种行为设计模式,它的主要目的是通过引入一个中介者对象来简化多个对象之间的交互,降低它们之间的耦合度。中介者模式使得这些对象可以通过中介者进行通信,而不需要直接相互引用,从而使得系统更加灵活和易于维护。
目的和意图
目的
- 减少对象之间的直接耦合:通过中介者对象来协调多个对象之间的交互,使得这些对象不需要直接引用彼此。
- 简化对象间的通信:对象只需要与中介者通信,而不需要知道其他对象的存在或如何与它们交互。
- 集中管理交互逻辑:将多个对象之间的交互逻辑集中到中介者中,使得交互逻辑更容易理解和管理。
意图
- 定义一个中介对象:中介者对象封装了对象之间的交互,使得对象之间的交互变得松散耦合。
- 促进松耦合:通过中介者,对象只与中介者耦合,而不是与多个其他对象耦合。
- 支持可扩展性:新的对象可以更容易地添加到系统中,而不需要修改现有的对象,只要它们与中介者进行交互。
适用场合
- 对象之间有复杂的引用关系:当系统中的对象之间存在复杂的引用关系,导致难以理解或维护时,可以使用中介者模式来简化这些关系。
- 需要控制对象之间的交互:当需要集中控制对象之间的交互逻辑时,中介者模式可以提供一个集中的地方来管理这些交互。
- 希望复用控制逻辑:如果多个场景需要类似的交互控制逻辑,可以将这些逻辑集中到中介者中,从而实现代码的复用。
- 对象间交互多变:当对象之间的交互可能随着需求的变化而变化时,中介者模式可以使得这些变化更容易管理。
中介者模式与外观模式的比较
相似点
- 抽象-layering:两者都旨在提供一个更高层次的抽象来简化与系统中一组对象的交互。
- 减少直接耦合:两者都试图减少系统中对象之间的直接耦合,通过引入一个新的对象来处理交互。
本质不同
-
目的不同:
- 中介者模式:主要目的是将多个对象之间的复杂交互逻辑集中到一个中介者对象中,以降低对象之间的耦合度,并使交互逻辑更易于管理和维护。
- 外观模式:主要目的是为子系统提供一个简化的接口,使得子系统的使用变得更加简单和直接,从而降低系统的复杂度。
-
角色不同:
- 中介者模式:包含中介者(Mediator)和同事(Colleague)对象,同事对象通过中介者进行交互。
- 外观模式:包含外观(Facade)和子系统(Subsystem)对象,外观对象提供了一个统一的接口来与子系统交互。
-
关注点不同:
- 中介者模式:关注于如何管理对象之间的交互,强调交互逻辑的集中管理。
- 外观模式:关注于如何简化子系统的接口,提供一个更易于使用的入口。
C++示例代码
以下是一个简单的C++示例,展示了中介者模式的应用。
场景
假设我们有一个简单的论坛系统,其中有多名用户可以发布帖子和回复。每个用户对象需要与其它用户交互,例如发送消息或接收消息。为了避免用户对象之间直接引用,我们可以引入一个中介者对象来管理这些交互。
实现
-
定义中介者接口
cppclass Mediator { public: virtual void send(const std::string& message, User* user) = 0; virtual ~Mediator() {} };
-
具体中介者类
cppclass ChatRoom : public Mediator { public: void send(const std::string& message, User* user) override { for (auto& u : users) { if (u != user) { u->receive(message); } } } void addUser(User* user) { users.push_back(user); } private: std::vector<User*> users; };
-
定义同事类
cppclass User { public: User(Mediator* mediator, const std::string& name) : mediator(mediator), name(name) {} void send(const std::string& message) { mediator->send(message, this); } void receive(const std::string& message) { std::cout << name << " received message: " << message << std::endl; } private: Mediator* mediator; std::string name; };
-
客户端代码
cppint main() { ChatRoom chatRoom; User user1(&chatRoom, "Alice"); User user2(&chatRoom, "Bob"); chatRoom.addUser(&user1); chatRoom.addUser(&user2); user1.send("Hi Bob!"); user2.send("Hello Alice!"); return 0; }
代码解释
- Mediator 接口:定义了发送消息的方法。
- ChatRoom 类:实现了 Mediator 接口,管理用户列表,并负责将消息分发给除了发送者之外的其他用户。
- User 类:用户类,通过中介者发送和接收消息。
- main 函数:创建 ChatRoom 和 User 对象,演示用户之间通过中介者发送消息。
通过这种方式,用户对象之间没有直接引用,而是通过中介者进行交互,从而降低了耦合度,使得系统更易于扩展和维护。
中介者模式(Mediator Pattern)经常与其他设计模式协同使用,以解决更复杂的设计问题。以下是几种常见的协同使用模式及其示例:
1. 中介者模式与观察者模式
目的
- 中介者模式:管理对象之间的交互,集中交互逻辑。
- 观察者模式:定义对象间的一对多依赖,当一个对象状态改变时,所有依赖它的对象都会收到通知。
适用场景
当系统中对象之间的交互不仅需要集中管理,而且需要在特定事件发生时通知多个对象时,可以结合使用中介者模式和观察者模式。
示例代码
假设我们有一个简单的股票交易系统,其中有多名交易员和多个股票。交易员可以订阅特定股票的报价,并在股票价格变化时收到通知。
cpp
#include <iostream>
#include <vector>
#include <string>
// 抽象中介者
class Mediator {
public:
virtual void subscribe(const std::string& stock, Observer* observer) = 0;
virtual void notify(const std::string& stock, double price) = 0;
virtual ~Mediator() {}
};
// 具体中介者
class StockExchange : public Mediator {
public:
void subscribe(const std::string& stock, Observer* observer) override {
observers[stock].push_back(observer);
}
void notify(const std::string& stock, double price) override {
for (auto observer : observers[stock]) {
observer->update(stock, price);
}
}
private:
std::map<std::string, std::vector<Observer*>> observers;
};
// 观察者接口
class Observer {
public:
virtual void update(const std::string& stock, double price) = 0;
virtual ~Observer() {}
};
// 具体观察者:交易员
class Trader : public Observer {
public:
Trader(const std::string& name) : name(name) {}
void update(const std::string& stock, double price) override {
std::cout << name << " received update: " << stock << " price is " << price << std::endl;
}
private:
std::string name;
};
int main() {
StockExchange exchange;
Trader trader1("Alice");
Trader trader2("Bob");
exchange.subscribe("AAPL", &trader1);
exchange.subscribe("GOOGL", &trader2);
exchange.subscribe("AAPL", &trader2);
exchange.notify("AAPL", 150.0);
exchange.notify("GOOGL", 2500.0);
return 0;
}
解释
- Mediator 接口:定义了订阅和通知的方法。
- StockExchange 类:实现了 Mediator 接口,管理观察者订阅和通知。
- Observer 接口:定义了更新方法。
- Trader 类:具体观察者,实现更新方法以接收股票价格变化通知。
- main 函数:创建 StockExchange 和 Trader 对象,演示交易员订阅股票并接收价格更新。
2. 中介者模式与策略模式
目的
- 中介者模式:管理对象之间的交互。
- 策略模式:定义一系列算法,封装起来,使其可以互换。
适用场景
当中介者需要根据不同的策略来处理对象之间的交互时,可以结合使用中介者模式和策略模式。
示例代码
假设我们有一个简单的任务分配系统,其中管理员可以分配任务给不同的员工,员工根据他们的能力和当前负荷来接受任务。管理员可以根据不同的策略来分配任务,例如基于员工的空闲时间或技能水平。
cpp
#include <iostream>
#include <vector>
#include <string>
// 策略接口
class AllocationStrategy {
public:
virtual Employee* allocateTask(const Task& task, const std::vector<Employee*>& employees) = 0;
virtual ~AllocationStrategy() {}
};
// 具体策略:基于空闲时间
class ByIdleTime : public AllocationStrategy {
public:
Employee* allocateTask(const Task& task, const std::vector<Employee*>& employees) override {
Employee* selected = nullptr;
int maxIdleTime = -1;
for (Employee* emp : employees) {
if (emp->idleTime > maxIdleTime) {
selected = emp;
maxIdleTime = emp->idleTime;
}
}
return selected;
}
};
// 具体策略:基于技能水平
class BySkillLevel : public AllocationStrategy {
public:
Employee* allocateTask(const Task& task, const std::vector<Employee*>& employees) override {
for (Employee* emp : employees) {
if (emp->skills.find(task.requiredSkill) != emp->skills.end()) {
return emp;
}
}
return nullptr;
}
};
// 抽象中介者
class Mediator {
public:
virtual void setAllocationStrategy(AllocationStrategy* strategy) = 0;
virtual void assignTask(const Task& task) = 0;
virtual ~Mediator() {}
};
// 具体中介者
class TaskAllocator : public Mediator {
public:
void setAllocationStrategy(AllocationStrategy* strategy) override {
this->strategy = strategy;
}
void assignTask(const Task& task) override {
Employee* selected = strategy->allocateTask(task, employees);
if (selected) {
selected->acceptTask(task);
} else {
std::cout << "No suitable employee found for task: " << task.description << std::endl;
}
}
void addEmployee(Employee* employee) {
employees.push_back(employee);
}
private:
AllocationStrategy* strategy;
std::vector<Employee*> employees;
};
// 员工类
class Employee {
public:
Employee(const std::string& name, int idleTime, const std::set<std::string>& skills)
: name(name), idleTime(idleTime), skills(skills) {}
void acceptTask(const Task& task) {
std::cout << name << " accepted task: " < < task.description << std::endl;
}
private:
std::string name;
int idleTime;
std::set<std::string> skills;
};
// 任务类
class Task {
public:
Task(const std::string& desc, const std::string& skill)
: description(desc), requiredSkill(skill) {}
std::string description;
std::string requiredSkill;
};
int main() {
TaskAllocator allocator;
Employee emp1("Alice", 5, {"C++", "Python"});
Employee emp2("Bob", 3, {"Python", "Java"});
allocator.addEmployee(&emp1);
allocator.addEmployee(&emp2);
// 使用基于空闲时间的策略
allocator.setAllocationStrategy(new ByIdleTime());
Task task1("Develop new feature", "C++");
allocator.assignTask(task1);
// 使用基于技能水平的策略
allocator.setAllocationStrategy(new BySkillLevel());
Task task2("Fix bug", "Python");
allocator.assignTask(task2);
return 0;
}
解释
- AllocationStrategy 接口:定义了任务分配策略。
- ByIdleTime 和 BySkillLevel 类:具体策略,根据空闲时间和技能水平分配任务。
- Mediator 接口:定义了设置策略和分配任务的方法。
- TaskAllocator 类:实现了 Mediator 接口,管理员工列表和任务分配。
- Employee 类:员工类,接受任务并处理。
- Task 类:任务类,包含描述和所需技能。
- main 函数:创建 TaskAllocator 和 Employee 对象,演示不同策略下的任务分配。
通过这种方式,中介者模式和策略模式结合使用,使得任务分配的逻辑既集中管理,又可以根据不同的策略灵活变化。