中介者模式
中介者模式又名调停者模式。将一个系统分割成许多对象通常可以增加其可复用性,但是对象间相互连接的激增又会降低其可复用性。因为大量的连接使得一个对象不可能在没有其它对象的支持下工作,系统表现为一个不可分割的整体,所以,对系统的行为进行任何较大的改动就十分困难了。解决这个问题的办法是两个类之间不直接进行通信,如果一个类需要调用另一个类的方法的话,可以通过第三者转发这个调用。通过中介者模式,可以将系统中的网状结构变成以中介者为中心的星状结构,每个具体的对象不再通过直接的联系与另一个对象发生相互作用,而是通过中介者对象与两一个对象发生相互作用。中介者对象的设计,使得系统的结构不会因为新对象的引入造成大量的修改工作。
中介者(Mediator)模式,用一个中介对象来封装一系列的对象交互。中介者使得各对象不需要显式的互相引用,从而使得其耦合松散,而且可以独立的改变他们之间的交互。
中介者模式的UML类图
Colleague叫做抽象同事类,而ConcreteColleague是具体同事类,每个具体同事只知道自己的行为,而不了解其他同事类的情况,但它们都认识中介者对象,Mediator是抽象中介者,定义了同事对象到中介者对象的接口,ConcreteMediator是具体中介者对象,实现抽象类的方法,它需要知道所有具体同事类,并从具体同事类接收消息,向具体同事对象发出命令。Mediator是否存在,取决于系统之后是否有扩展的可能,同事类发送消息,一般都是通过中介者对象来发送的,这意味着具体的同事类需要持有一个中介者对象。
中介者模式的优缺点
优点:
1.Meditor的出现减少了各个Colleague的耦合,使得可以独立的改变和复用各个Colleague类和Mediator。
2.由于把对象如何协作进行了抽象,将中介作为一个独立的概念并将其封装在一个对象中,这样关注的对象就从对象各自本身的行为转移到他们之间的交互上来,也就是站在一个更加宏观的角度来看待系统。
缺点:
1.由于ConcreteMediator控制集中化,于是把就把交互复杂性变成了中介者的复杂性,这就使得中介者会变的比任何一个Concrete都复杂。
使用场景:
1.中介者模式一般应用于一组对象以定义良好但是复杂的方式进行通信的场合,以及想定制一个分布在多个类中的行为,而又不想生成太多的子类的场合。
代码示例
问题模型:一个货运体系,有负责集中发布货运信息的中介公司(对应于中介者模式中的Mediator),有货主,当货主有货物需要运送时,要求自己注册过的中介公司发布这条货运信息,中介公司再负责把这条中介信息广播给所有向本公司注册过的火车司机。这里火车司机和货主就相当于是具体的同事类。
1.抽象同事类(UML类图中的Colleague类)

#ifndef COLLEAGUE_H_ #define COLLEAGUE_H_ //这个类即能代表货主也能代表货车司机,所以它需要同时具备接收消息和发送消息的能力 //在中介模式中消息的发送和接收都是通过中介者来完成的,具体同事类,发布消息时要委托中介者发布,而接收消息虽然是从中介者来接收,但实际上是从其它具体同事类那里接收信息的, //你可以把中介者当成一个布告牌 #include <string> class Mediator; class Colleague { protected: std::string m_strName; Mediator *m_Mediator{nullptr}; //使具体同事类认识中介者,在具体的同事类中,需要通过构造函数为它赋值 public: virtual void sendMessage(const std::string strMessgae) const = 0; //委托自己认识的中介者(m_Mediator)把这个消息发布出去 virtual void receiveMessage(const Colleague *objColleague,const std::string strMessage) const = 0; //通过中介者,接收来自于信息发布者的消息 virtual std::string getName() const = 0; Colleague() = default; virtual ~Colleague() = default; }; #endif
2.抽象中介者类(UML类图中的Mediator类)
抽象中介者需要知道一个同事列表,所以必然需要维护一个同事类的数组,以及同事类向中介者注册、注销自己的方法。此外,任何同事类的消息都将通过中介者转发,所以,中介者类还需要有一个Send方法负责转发消息。

#ifndef MEDIATOR_H_ #define MEDIATOR_H_ #include <list> #include <string> class Colleague; class Mediator { protected: std::list<Colleague *> m_listColleague; public: //货车司机向中介公司注册自己 void registerColleague(Colleague * objColleague) { m_listColleague.push_back(objColleague); } //货车司机从中介公司注销自己的账号 void removeColleague(Colleague *objColleague) { m_listColleague.remove(objColleague); } //中介公司接收货主的消息,并把这条消息转发给所有注册了的货车司机 virtual void distributeMessage(const Colleague *objColleagus,const std::string strMessage) const = 0; Mediator() = default; virtual ~Mediator() = default; }; #endif
3.具体同事类(UML类图中的ConcreteColleague类)

#ifndef CONCRETECOLLEAGUE_H_ #define CONCRETECOLLEAGUE_H_ //具体的同事类,在内部,具体的消息发送过程由中介者完成 #include "Colleague.h" #include <iostream> class Mediator; class ConcreteColleague : public Colleague { public: std::string getName() const override { return m_strName; } void sendMessage(const std::string strMessage) const override; void receiveMessage(const Colleague* objColleague,const std::string strMessage) const override; ConcreteColleague(Mediator * objMediator,const std::string strName) { m_Mediator = objMediator; m_strName = strName; } ~ConcreteColleague() = default; }; #endif #include "ConcreteColleague.h" #include "Mediator.h" //委托中介者将消息发布出去 void ConcreteColleague::sendMessage(const std::string strMessage) const { if(nullptr != m_Mediator) { m_Mediator->distributeMessage(this,strMessage); } } //接收从中介那里分发的来自于其它同事类的消息 void ConcreteColleague::receiveMessage(const Colleague* objColleague,const std::string strMessage) const { if(nullptr != m_Mediator) { std::cout << "Sender's Name is :"<< objColleague->getName() << "Message:" << strMessage << ".Receiver's name is :" << getName() << std::endl; } }
4.具体中介者类(UML类图中的ConcreteMediator类)

#ifndef CONCRETEMEDIATOR_H_ #define CONCRETEMEDIATOR_H_ #include "Mediator.h" //具体的中介者,在本例中,这个中介者的具体作用就是把来自于具体同事对象的消息,转发给出发布消息者之外,系统内的其它同事对象 class ConcreteMediator:public Mediator { public: void distributeMessage(const Colleague* objColleague,const std::string strMessage) const override; ConcreteMediator() = default; ~ConcreteMediator() = default; }; #endif #include "ConcreteMediator.h" #include "Colleague.h" void ConcreteMediator::distributeMessage(const Colleague* objColleague,const std::string strMessage) const { for(auto value : m_listColleague) { //使用条件判断,防止中介者将信息发布者回传给了自己 if(objColleague != value) { value->receiveMessage(objColleague,strMessage); } } }
5.Client

#include "ConcreteMediator.h" #include "ConcreteColleague.h" using namespace std; int main(int argc,char *argv[]) { //中介公司 ConcreteMediator objConcreteMediator; //货主,让货主认识中介公司 ConcreteColleague objConcreteColleague(&objConcreteMediator,"SenderA"); //货主向中介公司注册自己的账户 objConcreteMediator.registerColleague(&objConcreteColleague); //货车司机A,使得货车司机认识中介公司 ConcreteColleague objReceiverA(&objConcreteMediator,"ReceiverA"); //货车司机A向中介公司注册自己的账户 objConcreteMediator.registerColleague(&objReceiverA); //货车司机B,使得货车司机B认识中介公司 ConcreteColleague objReceiverB(&objConcreteMediator,"ReceiverB"); //货车司机B向中介公司注册自己的账户 objConcreteMediator.registerColleague(&objReceiverB); //货主委托中介公司将信息发布出去 objConcreteColleague.sendMessage("you ren ke yi bang wo ba zhe xie yu mi yun song dao qi tai xian ma?yun fei 1000/dun."); return (1); }