意图
中介者模式能让你减少对象之间混乱无序的依赖关系。该模式会限制对象之间的直接交互,迫使它们通过一个中介者对象进行合作。
问题
假如你有一个创建和修改客户资料的对话框,它由各种控件组成,例如文本框(TextField)、复选框(Checkbox)和按钮(Button)等。
如果直接在表单元素代码中实现业务逻辑,你将很难在程序其他表单中复用这些元素类,而且这种做法由于各控件耦合程度高,让程序发展变得混乱,很难地进行后续维护。
解决方案
中介者模式建议你停止组件之间的直接交流并使其相互独立。 这些组件必须调用特殊的中介者对象, 通过中介者对象重定向调用行为, 以间接的方式进行合作。 最终, 组件仅依赖于一个中介者类, 无需与多个其他组件相耦合。
中介者模式将原本多对多的网格结构转化为一对多的星形结构:
应用实例
机场调度系统:飞行器驾驶员们在靠近或离开空中管制区域时不会直接相互交流。但他们会与飞机跑道附近,塔台中的空管员通话。
MVVM 框架,其中VM(视图模型)就是 M(模型)和 V(视图)的中介者。
中介者模式结构
示例
#include <iostream>
#include <string>
/**
* The Mediator interface declares a method used by components to notify the
* mediator about various events. The Mediator may react to these events and
* pass the execution to other components.
*/
class BaseComponent;
class Mediator {
public:
virtual void Notify(BaseComponent *sender, std::string event) const = 0;
};
/**
* The Base Component provides the basic functionality of storing a mediator's
* instance inside component objects.
*/
class BaseComponent {
protected:
Mediator *mediator_;
public:
BaseComponent(Mediator *mediator = nullptr) : mediator_(mediator) {
}
void set_mediator(Mediator *mediator) {
this->mediator_ = mediator;
}
};
/**
* Concrete Components implement various functionality. They don't depend on
* other components. They also don't depend on any concrete mediator classes.
*/
class Component1 : public BaseComponent {
public:
void DoA() {
std::cout << "Component 1 does A.\n";
this->mediator_->Notify(this, "A");
}
void DoB() {
std::cout << "Component 1 does B.\n";
this->mediator_->Notify(this, "B");
}
};
class Component2 : public BaseComponent {
public:
void DoC() {
std::cout << "Component 2 does C.\n";
this->mediator_->Notify(this, "C");
}
void DoD() {
std::cout << "Component 2 does D.\n";
this->mediator_->Notify(this, "D");
}
};
/**
* Concrete Mediators implement cooperative behavior by coordinating several
* components.
*/
class ConcreteMediator : public Mediator {
private:
Component1 *component1_;
Component2 *component2_;
public:
ConcreteMediator(Component1 *c1, Component2 *c2) : component1_(c1), component2_(c2) {
this->component1_->set_mediator(this);
this->component2_->set_mediator(this);
}
void Notify(BaseComponent *sender, std::string event) const override {
if (event == "A") {
std::cout << "Mediator reacts on A and triggers following operations:\n";
this->component2_->DoC();
}
if (event == "D") {
std::cout << "Mediator reacts on D and triggers following operations:\n";
this->component1_->DoB();
this->component2_->DoC();
}
}
};
/**
* The client code.
*/
void ClientCode() {
Component1 *c1 = new Component1;
Component2 *c2 = new Component2;
ConcreteMediator *mediator = new ConcreteMediator(c1, c2);
std::cout << "Client triggers operation A.\n";
c1->DoA();
std::cout << "\n";
std::cout << "Client triggers operation D.\n";
c2->DoD();
delete c1;
delete c2;
delete mediator;
}
int main() {
ClientCode();
return 0;
}
}
执行结果:
Client triggers operation A.
Component 1 does A.
Mediator reacts on A and triggers following operations:
Component 2 does C.
Client triggers operation D.
Component 2 does D.
Mediator reacts on D and triggers following operations:
Component 1 does B.
Component 2 does C.
小结
适合应用场景
-
当一些对象和其他对象紧密耦合以致难以对其进行修改时, 可使用中介者模式。
-
当组件因过于依赖其他组件而无法在不同应用中复用时, 可使用中介者模式。
-
如果为了能在不同情景下复用一些基本行为, 导致你需要被迫创建大量组件子类时, 可使用中介者模式。
优点
-
单一职责原则。 你可以将多个组件间的交流抽取到同一位置, 使其更易于理解和维护。
-
开闭原则。 你无需修改实际组件就能增加新的中介者。
-
你可以减轻应用中多个组件间的耦合情况,更方便地复用各个组件。
缺点
- 中介者可能会演化成为上帝对象使得让中介者庞变得复杂难以维护。(上帝对象(God object)是一个了解过多或者负责过多的对象。)
参考
22种设计模式:refactoringguru.cn/design-patterns
《设计模式:可复用面向对象软件的基础》