什么是中介者模式?
中介者模式(Mediator Pattern)是用来降低多个对象和类之间的通信复杂性。这种模式提供了一个中介类,该类通常处理不同类之间的通信,并支持松耦合,使代码易于维护,能让你减少对象之间混乱无序的依赖关系。 该模式会限制对象之间的直接交互, 迫使它们通过一个中介者对象进行合作。
在软件系统中,经常会出现多个对象之间存在复杂的交互关系,这种交互关系常常是"网状结构",导致对象之间存在过多的相互引用和依赖关系。这种高度耦合的设计方案将会给未来的改变和维护带来很大的挑战。
中介者模式建议你停止组件之间的直接交流并使其相互独立。 这些组件必须调用特殊的中介者对象, 通过中介者对象重定向调用行为, 以间接的方式进行合作。 最终, 组件仅依赖于一个中介者类, 无需与多个其他组件相耦合。
中介者模式适合应用场景
1.当一些对象和其他对象紧密耦合以致难以对其进行修改时, 可使用中介者模式。
该模式让你将对象间的所有关系抽取成为一个单独的类, 以使对于特定组件的修改工作独立于其他组件。
2.当组件因过于依赖其他组件而无法在不同应用中复用时, 可使用中介者模式。
应用中介者模式后, 每个组件不再知晓其他组件的情况。 尽管这些组件无法直接交流, 但它们仍可通过中介者对象进行间接交流。 如果你希望在不同应用中复用一个组件, 则需要为其提供一个新的中介者类。
3. 如果为了能在不同情景下复用一些基本行为, 导致你需要被迫创建大量组件子类时, 可使用中介者模式。
由于所有组件间关系都被包含在中介者中, 因此你无需修改组件就能方便地新建中介者类以定义新的组件合作方式。
注意事项:不应当在职责混乱的时候使用。
实现方式
-
找到一组当前紧密耦合, 且提供其独立性能带来更大好处的类 (例如更易于维护或更方便复用)。
-
声明中介者接口并描述中介者和各种组件之间所需的交流接口。 在绝大多数情况下, 一个接收组件通知的方法就足够了。
如果你希望在不同情景下复用组件类, 那么该接口将非常重要。 只要组件使用通用接口与其中介者合作, 你就能将该组件与不同实现中的中介者进行连接。
-
实现具体中介者类。 该类可从自行保存其下所有组件的引用中受益。
-
组件必须保存对于中介者对象的引用。 该连接通常在组件的构造函数中建立, 该函数会将中介者对象作为参数传递。
-
修改组件代码, 使其可调用中介者的通知方法, 而非其他组件的方法。 然后将调用其他组件的代码抽取到中介者类中, 并在中介者接收到该组件通知时执行这些代码。
参与者
- Mediator(中介者):定义了同事对象之间通信的接口。
- ConcreteMediator(具体中介者):实现中介者接口,协调各个同事对象之间的交互。
- Colleague(同事类):各个需要通过中介者进行通信的对象。它们只知道中介者,而不知道其他同事对象的存在。
示例代码:
中介者接口:
#include <iostream>
#include <string>
#include <vector>
#include <memory>
class Colleague;
class Mediator {
public:
virtual void send(const std::string& message, Colleague* colleague) = 0;
virtual ~Mediator() = default;
};
同事类:
class Colleague {
protected:
Mediator* mediator;
std::string name;
public:
Colleague(const std::string& name) : name(name), mediator(nullptr) {}
void setMediator(Mediator* mediator) {
this->mediator = mediator;
}
std::string getName() const {
return name;
}
virtual void send(const std::string& message) {
if (mediator) {
mediator->send(message, this);
}
}
virtual void receive(const std::string& message) {
std::cout << name << " received: " << message << std::endl;
}
};
具体中介者:
class ChatMediator : public Mediator {
private:
std::vector<Colleague*> colleagues;
public:
void addColleague(Colleague* colleague) {
colleagues.push_back(colleague);
colleague->setMediator(this);
}
void send(const std::string& message, Colleague* sender) override {
for (Colleague* colleague : colleagues) {
if (colleague != sender) {
colleague->receive(sender->getName() + ": " + message);
}
}
}
};
使用示例:
int main() {
ChatMediator chatMediator;
Colleague alice("Alice");
Colleague bob("Bob");
Colleague charlie("Charlie");
chatMediator.addColleague(&alice);
chatMediator.addColleague(&bob);
chatMediator.addColleague(&charlie);
alice.send("Hello, everyone!");
bob.send("Hey Alice!");
charlie.send("Hi Bob and Alice!");
return 0;
}
运行结果:
Bob received: Alice: Hello, everyone!
Charlie received: Alice: Hello, everyone!
Alice received: Bob: Hey Alice!
Charlie received: Bob: Hey Alice!
Alice received: Charlie: Hi Bob and Alice!
Bob received: Charlie: Hi Bob and Alice!
中介者模式优缺点
优点:
- 单一职责原则。 你可以将多个组件间的交流抽取到同一位置, 使其更易于理解和维护。
- 开闭原则。 你无需修改实际组件就能增加新的中介者。
- 你可以减轻应用中多个组件间的耦合情况。
- 你可以更方便地复用各个组件。
缺点:
- 中介者会庞大,变得复杂难以维护。
- 一段时间后, 中介者可能会演化成上帝对象。
总结
中介者模式通过引入一个中介者对象,简化了对象之间的交互,降低了耦合度。使用中介者模式后,各个对象只需与中介者打交道,而无需了解其他对象的存在。这使得系统更易于扩展和维护。在实际开发中,中介者模式特别适用于复杂对象交互的场景,如聊天室、MVC框架等。