一,中介者模式的定义
中介者模式是一种行为型设计模式。它通过一个中介者对象将多个对象之间的交互关系进行封装,使得对象之间的交互需要通过中介者对象来完成。该设计模式的结构很容易理解,以中介者为中心。
中介者模式的设计思想侧重于在对象之间增加一个用来调度的中介。
有了中介者模式,各个对象可以专注于各自的业务处理逻辑,而不需要关心通信的具体实现细节。
中介者模式在现实生活中的抽象实例:
航空管制系统:航空管制系统作为中介者,协调飞机、航空公司和机场的通信和协作。
交易系统:在金融领域,交易系统将银行、金融机构、客户等各个参与者进行协调,确保资金的安全快速转移。
买房中介:买房中介充当着买卖双方之间的桥梁和调解者的角色,确保双方利益的平衡和交易的顺利进行。
二,中介者模式的结构
中介者模式主要包含以下组件:
1.抽象中介者(Mediator):定义了对象之间相互通信的规则,定义了管理对象和消息通信的统一接口。
2.抽象同事对象(Colleague):是参与通信的各个对象,内部包含对中介者对象的引用。负责将消息发送给中介者,以及接收并处理中介者发来的消息。
3.具体中介者(Concrete Mediator):包含对抽象中介者的具体实现,负责协调各个对象之间的通信,协调的方式以转发消息为主。
4.具体同事对象(Concrete Colleague):包含对抽象同事对象的具体实现。它们之间通过调用中介者的接口进行通信,并接收和处理中介者转发给它们的消息。
组件之间的工作步骤如下:
1.初始化中介者对象。
2.各个同事对象与中介者关联,将中介者对象传递给各个同事对象。
3.同事对象与中介者通信,同事对象调用中介者对象提供的通信接口,由中介者负责将信息转发给目标同事对象。
对应UML类图:
三,中介者模式代码样例
cpp
#include <iostream>
#include <string>
#include <vector>
class Colleague;
class Mediator{
public:
virtual void sendMessage(const std::string& msg, Colleague* colleague) = 0;
virtual void addColleague(Colleague* colleague) = 0;
};
class Colleague{
public:
Colleague(Mediator* mediator) : mediator_(mediator) {}
virtual void sendMessage(const std::string& message) = 0;
virtual void receiveMessage(const std::string& message) = 0;
protected:
Mediator* mediator_;
};
class ConcreteMediator : public Mediator{
public:
void sendMessage(const std::string& msg, Colleague* colleague) override
{
for (auto col : colleagues_) {
if (col != colleague) {
col->receiveMessage(msg);
}
}
}
void addColleague(Colleague* colleague) override {
colleagues_.push_back(colleague);
}
private:
std::vector<Colleague*> colleagues_;
};
class ConcreteColleague : public Colleague{
public:
ConcreteColleague(Mediator* mediator) : Colleague(mediator) {}
void sendMessage(const std::string& message) override {
mediator_->sendMessage(message, this);
}
void receiveMessage(const std::string& message) override {
std::cout << "Received message: " << message << std::endl;
}
};
int main() {
Mediator* mediator = new ConcreteMediator();
Colleague* colleague1 = new ConcreteColleague(mediator);
Colleague* colleague2 = new ConcreteColleague(mediator);
mediator->addColleague(colleague1);
mediator->addColleague(colleague2);
colleague1->sendMessage("Hello from colleague1");
colleague2->sendMessage("Hello from colleague2");
delete colleague1;
delete colleague2;
delete mediator;
return 0;
}
运行结果:
bash
Received message: Hello from colleague1
Received message: Hello from colleague2
四,中介者模式的应用场景
事件驱动架构:应用程序中,按钮点击等事件不需要直接关联所有处理响应的逻辑,而是通过一个"事件总线"或"消息中间件"来分发消息。
GUI用户界面:在UI组件间传递事件或更新状态时,可以使用中介者模式避免硬编码依赖。
分布式系统:分布式应用中设定一个集中式的服务器作为中介,协调客户端之间的交互。
消息队列:在异步通信场景,发送者和接收者通过一个消息中间件来传递信息,方便解耦和事务管理。
五,中介者模式的优缺点
中介者模式的优点:
降低了对象之间的耦合,易于维护。
可以实现对通信的集中控制。
方便随时修改和消息对应的事件处理。
在不改变原有对象的基础上,可以灵活添加新的消息类型。
中介者模式的缺点:
容易导致对系统的过度设计。
当对象很多时,中介者会变得复杂和难以管理。
通信期间需要额外的调度,性能开销大。
六,代码实战
Demo1:基于中介者模式实现的消息群发功能
cpp
#include <iostream>
#include <string>
#include <vector>
class User;
class Mediator {
public:
virtual void sendMessage(const std::string& message, User* user) = 0;
virtual void addUser(User* user) = 0;
};
class User {
public:
User(const std::string& name, Mediator* mediator){
this->name = name;
this->mediator = mediator;
}
const std::string& getName() const {
return name;
}
void sendMessage(const std::string& message) {
mediator->sendMessage(message, this);
}
virtual void receiveMsg(const std::string& message) = 0;
private:
std::string name;
Mediator* mediator;
};
class ChatRoom : public Mediator {
public:
void addUser(User* user) {
users.push_back(user);
}
void sendMessage(const std::string& message, User* sender) override {
for (User* user : users) {
if (user != sender) {
user->receiveMsg(message);
}
}
}
private:
std::vector<User*> users;
};
class ChatUser : public User {
public:
ChatUser(const std::string& name, Mediator* mediator) : User(name, mediator) {}
void receiveMsg(const std::string& msg) override {
std::cout << getName() << " received a message: " << msg << std::endl;
}
};
int main() {
Mediator* chatRoom = new ChatRoom();
User* user1 = new ChatUser("User1", chatRoom);
User* user2 = new ChatUser("User2", chatRoom);
User* user3 = new ChatUser("User3", chatRoom);
chatRoom->addUser(user1);
chatRoom->addUser(user2);
chatRoom->addUser(user3);
user1->sendMessage("Hello, everyone!");
delete user1;
delete user2;
delete user3;
delete chatRoom;
return 0;
}
运行结果:
bash
User2 received a message: Hello, everyone!
User3 received a message: Hello, everyone!
Demo2:模拟的聊天室
cpp
#include <iostream>
#include <string>
#include <vector>
using namespace std;
struct ChatRoom {
virtual void broadcast(string from, string msg) = 0;
virtual void message(string from, string to, string msg) = 0;
};
struct Person {
string m_name;
ChatRoom* m_room{ nullptr };
vector<string> m_chat_log;
Person(string n) : m_name(n) {}
void say(string msg) const {
m_room->broadcast(m_name, msg);
}
void pm(string to, string msg) const {
m_room->message(m_name, to, msg);
}
void receive(string from, string msg) {
string s{ from + ": \"" + msg + "\"" };
cout << "[" << m_name << "'s chat session]" << s << "\n";
m_chat_log.emplace_back(s);
}
};
struct GoogleChat: ChatRoom
{
vector<Person*> m_people;
void broadcast(string from, string msg) {
for (auto p : m_people)
if (p->m_name != from)
p->receive(from, msg);
}
void join(Person* p) {
string join_msg = p->m_name + " joins the chat";
broadcast("room", join_msg);
p->m_room = this;
m_people.push_back(p);
}
void message(string from, string to, string msg) {
auto target = find_if(begin(m_people), end(m_people),
[&](const Person* p) {
return p->m_name == to;
});
if (target != end(m_people)) (*target)->receive(from, msg);
}
};
int main() {
GoogleChat room;
Person john{ "John" };
Person jane{ "Jane" };
room.join(&john);
room.join(&jane);
john.say("hi room");
jane.say("oh, hey john");
Person simon{ "Simon" };
room.join(&simon);
simon.say("hi everyone!");
jane.pm("Simon", "glad you found us, simon!");
return EXIT_SUCCESS;
}
运行结果:
bash
[John's chat session]room: "Jane joins the chat"
[Jane's chat session]John: "hi room"
[John's chat session]Jane: "oh, hey john"
[John's chat session]room: "Simon joins the chat"
[Jane's chat session]room: "Simon joins the chat"
[John's chat session]Simon: "hi everyone!"
[Jane's chat session]Simon: "hi everyone!"
[Simon's chat session]Jane: "glad you found us, simon!"
七,参考阅读
https://www.geeksforgeeks.org/mediator-design-pattern/
https://www.patterns.dev/vanilla/mediator-pattern/
https://vishalchovatiya.com/posts/mediator-design-pattern-in-modern-cpp/
https://softwarepatterns.com/cpp/mediator-software-pattern-cpp-example