设计模式之中介者
一、中介者设计模式概念
中介者模式(Mediator) 是一种行为设计模式, 能让你减少对象之间混乱无序的依赖关系。 该模式会限制对象之间的直接交互, 迫使它们通过一个中介者对象进行合作。
适用场景
- 当一些对象和其他对象紧密耦合以致难以对其进行修改时, 可使用中介者模式。
- 当组件因过于依赖其他组件而无法在不同应用中复用时, 可使用中介者模式。
- 如果为了能在不同情景下复用一些基本行为, 导致你需要被迫创建大量组件子类时, 可使用中介者模式
中介者设计模式的结构:
- 组件 (Component) 是各种包含业务逻辑的类。 每个组件都有一个指向中介者的引用, 该引用被声明为中介者接口类型。 组件不知道中介者实际所属的类, 因此你可通过将其连接到不同的中介者以使其能在其他程序中复用。
- 中介者 (Mediator) 接口声明了与组件交流的方法, 但通常仅包括一个通知方法。 组件可将任意上下文 (包括自己的对象) 作为该方法的参数, 只有这样接收组件和发送者类之间才不会耦合。
- 具体中介者 (Concrete Mediator) 封装了多种组件间的关系。 具体中介者通常会保存所有组件的引用并对其进行管理, 甚至有时会对其生命周期进行管理。
- 组件并不知道其他组件的情况。 如果组件内发生了重要事件, 它只能通知中介者。 中介者收到通知后能轻易地确定发送者, 这或许已足以判断接下来需要触发的组件了。
- 对于组件来说, 中介者看上去完全就是一个黑箱。 发送者不知道最终会由谁来处理自己的请求, 接收者也不知道最初是谁发出了请求。
代码如下:
问题:实现一个机场的起飞管理系统,如果由驾驶员自己管理,会导致混乱,因此需要一个中介者来管理。
解决方案:用一个中介对象来封装一系列的对象交互。中介者使各对象不需要显式地相互引用,从而使耦合松散,而且可以独立地改变他们之间的交互。
中介者模式可帮助你减少各种UI组件之间的互相依赖关系。
#include <iostream>
#include <string>
class Staff;
class ControllerTower
{
public:virtual void notify(Staff* staff, std::string event)const = 0;
};
class Staff
{
protected:ControllerTower* m_controltower;std::string m_name;
public:Staff( std::string name, ControllerTower* controltower = nullptr) :m_name(name), m_controltower(controltower) {}std::string name() const {return m_name;}void setMediator(ControllerTower* controltower) {m_controltower = controltower;}
};class Pilot : public Staff
{
public:Pilot(std::string name) : Staff(name) {}void takeoff() {std::cout << name() << " 请求起飞." << std::endl;m_controltower->notify(this, "请求起飞");}void copy() {std::cout << name() << " is copying." << std::endl;}
};class GroundGrew : public Staff
{
public:GroundGrew(std::string name) : Staff(name) {}void maintainance() {std::cout << name() << " 请求维护." << std::endl;m_controltower->notify(this, "请求维护");}void copy() {std::cout << name() << " is copying." << std::endl;}
};class ControllerTower1 : public ControllerTower
{
private:Pilot* m_pilot1;Pilot* m_pilot2;Pilot* m_pilot3;GroundGrew* m_groundgrew1;
public:ControllerTower1(Pilot* pilot1, Pilot* pilot2, Pilot* pilot3, GroundGrew* groundgrew1): m_pilot1(pilot1), m_pilot2(pilot2), m_pilot3(pilot3), m_groundgrew1(groundgrew1) {m_pilot1->setMediator(this);m_pilot2->setMediator(this);m_pilot3->setMediator(this);m_groundgrew1->setMediator(this);}void notify(Staff* staff, std::string event)const override {std::cout << "控制塔:飞行员" << staff->name() << event << std::endl;if (event == "请求起飞"){m_groundgrew1->copy();if (staff != m_pilot1)m_pilot1->copy();if (staff != m_pilot2)m_pilot2->copy();if (staff != m_pilot3)m_pilot3->copy();}if (event == "请求维护"){m_pilot1->copy();m_pilot2->copy();m_pilot3->copy();}}
};
int main()
{Pilot* p1 = new Pilot("p1");Pilot* p2 = new Pilot("p2");Pilot* p3 = new Pilot("p3");GroundGrew* g1 = new GroundGrew("g1");ControllerTower1* controltower = new ControllerTower1(p1, p2, p3, g1);p1->takeoff();g1->maintainance();delete p1;delete p2;delete p3;delete g1;return 0;
}
二、与其他模式的关系
- 责任链模式 (opens new window)、 命令模式 (opens new window)、 中介者模式 (opens new window)和观察者模式 (opens new window)用于处理请求发送者和接收者之间的不同连接方式:
- 责任链按照顺序将请求动态传递给一系列的潜在接收者, 直至其中一名接收者对请求进行处理。
- 命令在发送者和请求者之间建立单向连接。
- 中介者清除了发送者和请求者之间的直接连接, 强制它们通过一个中介对象进行间接沟通。
- 观察者允许接收者动态地订阅或取消接收请求。
- 外观模式 (opens new window)和中介者 (opens new window)的职责类似: 它们都尝试在大量紧密耦合的类中组织起合作。
- 外观为子系统中的所有对象定义了一个简单接口, 但是它不提供任何新功能。 子系统本身不会意识到外观的存在。 子系统中的对象可以直接进行交流。
- 中介者将系统中组件的沟通行为中心化。 各组件只知道中介者对象, 无法直接相互交流。
- 中介者 (opens new window)和观察者 (opens new window)之间的区别往往很难记住。 在大部分情况下, 你可以使用其中一种模式, 而有时可以同时使用。 让我们来看看如何做到这一点。
- 中介者的主要目标是消除一系列系统组件之间的相互依赖。 这些组件将依赖于同一个中介者对象。 观察者的目标是在对象之间建立动态的单向连接, 使得部分对象可作为其他对象的附属发挥作用。
- 有一种流行的中介者模式实现方式依赖于观察者。 中介者对象担当发布者的角色, 其他组件则作为订阅者, 可以订阅中介者的事件或取消订阅。 当中介者以这种方式实现时, 它可能看上去与观察者非常相似。
- 当你感到疑惑时, 记住可以采用其他方式来实现中介者。 例如, 你可永久性地将所有组件链接到同一个中介者对象。 这种实现方式和观察者并不相同, 但这仍是一种中介者模式。
- 假设有一个程序, 其所有的组件都变成了发布者, 它们之间可以相互建立动态连接。 这样程序中就没有中心化的中介者对象, 而只有一些分布式的观察者。