第25章 世界需要和平--中介者模式
25.1 世界需要和平
由于各国之间代表的利益不同,所以矛盾冲突是难免的,但如果有这样一个组织,由各国的代表组成,用来维护国际和平与安全,解决国际间经济,社会,文化和人道主义性质的问题,这样的类似联合国的组织就是一个调停者,中介者模式。
国与国之间的关系,就类似于不同的对象与对象之间的关系,这就要求对象之间需要知道其他所有对象,尽管将一个系统分割成许多对象通常可以增加其可复用性,但是对象之间相互连接的激增又会降低其可复用性了。因为大量的连接使得一个对象不可能在没有其他对象的支持下工作,系统表现为一个不可分割的整体,所以系统的行为进行任何较大的改动就十分困难了。
通过中介者对象,可以将系统的网状结构变成以中介者为中心的星形结构,每个具体对象不再通过直接的联系与另一个对象发生相互作用,而是通过中介者对象与另一个对象发生相互作用。中介者对象的设计,使得系统的结构不会因为新对象的引入造成大量的修改工作。
25.2 中介者模式
用一个中介对象来封装一系列的对象交互。中介者使对象不需要显式地相互引用,从而使其耦合性松散,而且可以独立地改变它们之间的交互。
#include "Mediator.h" #include "Colleague.h" void ConcreteMediator::SetConcreteColleague1(ConcreteColleague1* p) { m_pColleague1 = p; } void ConcreteMediator::SetConcreteColleague2(ConcreteColleague2* p) { m_pColleague2 = p; } void ConcreteMediator::Send(std::string message, Colleague* colleague) { if (colleague == (Colleague*)m_pColleague1) { m_pColleague2->Noitfy(message); } else if (colleague == (Colleague*)m_pColleague2) { m_pColleague1->Noitfy(message); } }
#pragma once #include <string> class Colleague; class ConcreteColleague1; class ConcreteColleague2; //抽象中介类 class Mediator { public: //定义一个抽象的发送消息的方法,得到同事对象和发送信息 virtual void Send(std::string message, Colleague* colleague) = 0; }; //具体中介类 class ConcreteMediator : public Mediator { public: //需要了解所有的具有同事对象 void SetConcreteColleague1(ConcreteColleague1* p); void SetConcreteColleague2(ConcreteColleague2* p); //重写发送信息的方法,根据对象做出选择判断,通知对象 void Send(std::string message, Colleague* colleague); private: //具体对象的指针 ConcreteColleague1* m_pColleague1; ConcreteColleague2* m_pColleague2; };
#pragma once #include <string> #include <iostream> #include "Mediator.h" class Mediator; //抽象同事类 class Colleague { public: Colleague(Mediator * mediator) {//构造方法,得到中介者对象 m_Mediator = mediator; }; protected: Mediator* m_Mediator; }; //具体同事类1 class ConcreteColleague1 : public Colleague { public: ConcreteColleague1(Mediator * mediator) :Colleague(mediator) { }; void Send(std::string message) { //通过中介者发送消息 this->m_Mediator->Send(message, this); }; void Noitfy(std::string message) { std::cout << "ConcreteColleague1 is Get This Message" << message << std::endl; }; }; //具体同事类2 class ConcreteColleague2 : public Colleague { public: ConcreteColleague2(Mediator * mediator) :Colleague(mediator) { }; void Send(std::string message) { //通过中介者发送消息 this->m_Mediator->Send(message, this); }; void Noitfy(std::string message) { std::cout << "ConcreteColleague2 is Get This Message" << message << std::endl; }; };
客户端
#include "stdafx.h" #include "Colleague.h" #include "Mediator.h" int _tmain(int argc, _TCHAR* argv[]) { //中介者 ConcreteMediator* pMediator = new ConcreteMediator(); //同事类 ConcreteColleague1* pColleague1 = new ConcreteColleague1(pMediator); ConcreteColleague2* pColleague2 = new ConcreteColleague2(pMediator); //让两个同事类认识中介者对象 pMediator->SetConcreteColleague1(pColleague1); pMediator->SetConcreteColleague2(pColleague2); //具体同事类的发送消息都是通过中介者转发 pColleague1->Send("Are you eat Lunch?"); pColleague2->Send("No,I am Not. How about you?"); delete pMediator; delete pColleague1; delete pColleague2; return 0; }
由于有了Mediator,使得ConcreteColleague1和ConcreteColleague2在发送消息和接收信息时其实是通过中介者来完成的,这就减少了他们之间的耦合度了。
25.3 安理会做中介
#pragma once #include <string> #include <iostream> //the same as Mediator class class Country; //联合国机构 class UnitedNations { public: //声明 virtual void Declare(std::string message, Country* colleague) = 0; }; //国家 class Country { public: Country(UnitedNations* p) { m_UnitedNations = p; }; protected: //联合国 UnitedNations* m_UnitedNations; }; //美国类 class USA : public Country { public: USA(UnitedNations* p) :Country(p) { }; //声明 void Declare(std::string message) { m_UnitedNations->Declare(message, this); }; //获得消息 void GetMessage(std::string message) { std::cout << "USA is received message:" << message << std::endl; } }; //利拉克类 class Iraq : public Country { public: Iraq(UnitedNations* p) :Country(p) { }; //声明 void Declare(std::string message) { m_UnitedNations->Declare(message, this); }; //获得消息 void GetMessage(std::string message) { std::cout << "Iraq is received message:" << message << std::endl; } }; //联合国安全理事会 class UnitedNationsSecurityCouncil : public UnitedNations { public: //声明 void Declare(std::string message, Country* colleague) { if ((USA*)colleague == m_pUSA) { m_pIraq->GetMessage(message); } else if ((Iraq*)colleague == m_pIraq) { m_pUSA->GetMessage(message); } }; //美国 void SetUSAColleague(USA* p) { m_pUSA = p; }; //利拉克 void SetIraqColleague(Iraq* p) { m_pIraq = p; }; private: USA* m_pUSA; Iraq* m_pIraq; };
客户端
#include "stdafx.h" #include "Mediator.h" int _tmain(int argc, _TCHAR* argv[]) { UnitedNationsSecurityCouncil* pMediator = new UnitedNationsSecurityCouncil(); USA* pUSA = new USA(pMediator); Iraq* pIraq = new Iraq(pMediator); pMediator->SetIraqColleague(pIraq); pMediator->SetUSAColleague(pUSA); pUSA->Declare("不准研制核武器,否则要发动战争"); pIraq->Declare("我们没有核武器,也不怕侵略"); return 0; }
其实最关键的问题在于ConcreteMediator这个类必须要知道所有的ConcreteColleague,于是使得ConcreteMediator的责任太多了,如果它出了问题,则整个系统都会有问题了。如果安理会出了问题,当然会对世界都造成影响。
25.4 中介者模式优缺点
中介者模式很容易在系统中应用,也很容易在系统中误用。当系统出现了"多对多"交互复杂的对象群时,不要急于使用中介者模式,而要先反思你的系统在设计上是不是合理。
中介者模式的优点就是Mediator的出现减少了各个Colleague的耦合,使得可以独立地改变和复用各个Colleague类和Mediator,比如任何国家的改变不会改变到其他国家,而只是与安理会发生变化。由于把对象如何协作进行了抽象,将中介作为一个独立的概念并将其封装在一个对象中,这样关注的对象就从对象各自本身的行为转移到他们之间的交互上来,也就是站在一个更宏观的角度去看待系统。比如巴以冲突,本来只能算是国与国之间的矛盾,因此各自的看法可能都比较狭隘,但站在联合国安理会的角度,就可以从全球化,也更客观角度来看待这个问题,在调停和维和上做出贡献。
中介者模式的缺点:由于ConcreteMediator控制了集中化,于是就把交互复杂性变为了中介者的复杂性,这就使得中介者会变得比任何一个ConcreteColleague都复杂。中介者模式的优点来自集中控制,缺点也是集中控制。
中介者模式一般应用于一组对象以定义良好但是复杂方式进行通信的场合,以及想订制一个分布在多个类中的行为,而又不想生成太多的子类的场合。
比如Windows中的计算器,Button类是不知道Display类的,所有的时间的执行都是在Form窗体的代码中完成,也就是说所有的控件的交互都是由Form窗体来作中介,操作各个对象,这的确是典型的中介者模式的应用。