# 中介者模式,说一说贝壳找房 ![avatar](https://github.com/FengJungle/DesignPattern/blob/master/18.MediatorPattern/1.Picture/%E4%B8%AD%E4%BB%8B%E8%80%85%E6%A8%A1%E5%BC%8F.jpg) ``` 离开学校参加工作之前,你一定是有一段时间是在找租,Jungle也是如此。 Jungle为了找到合适的房子,沿着地铁线一个小区一个小区的去问门卫问保安,或者照着小区门口展板上的房东的联系方式去找房东……此事已经过去大半年了,但Jungle现在想来还是觉得很麻烦!麻烦在哪里?得亲自走亲自联系各个房东,通信录和微信得加好多房东…… 其实有更省事的办法,那就是找中介,租房中介哪儿都是。虽然贵(主要原因),但是的确为租客省了很多事,其实也为房东省了很多事。 ``` ![avatar](https://github.com/FengJungle/DesignPattern/blob/master/18.MediatorPattern/1.Picture/%E4%B8%AD%E4%BB%8B%E8%80%85%E4%B8%BE%E4%BE%8B%E5%9B%BE.png) ## 1.中介者模式简介 上述Jungle租房的例子如上图,如果Jungle自己去租房,得和各个房东亲自交互,如果另一个租客贱萌兔也在自己找房,同样也得和很多房东打交道。房东也是一样,得和众多不同的租客联系。**如果有中介者了,房东们只需要去中介者那里注册一下,自己的房子在哪儿、什么户型设施、价格多少,就ok了;Jungle和贱萌兔也只需要和一个人打交道,那就是中介。中介的出现使两边都省去了不少事**。 软件设计模式中,也有一种类似的解决方案,那就是中介者模式—— ``` 中介者模式: 定义一个对象来封装一系列对象的交互。中介者模式使各个对象之间不需要显示地相互引用,从而使其耦合松散,而且用户可以独立地改变它们之间的交互。 ``` 如果一个系统里各个对象之间存在多对多的相互关系,可以将对象之间的一些交互行为从各个对象中分离出来,集中封装在一个中介者对象中,使其耦合松散,并由中介者统一协调。通过中介者,对象之间的多对多关系就简化了相对更简单的一对多关系。 ## 2.中介者模式结构 中介者模式的UML图如下,为了便于扩展,系统引入了抽象中介者。 ![avatar](https://github.com/FengJungle/DesignPattern/blob/master/18.MediatorPattern/1.Picture/%E4%B8%AD%E4%BB%8B%E8%80%85%E6%A8%A1%E5%BC%8FUML%E5%9B%BE.png) 由图可知,中介者模式主要有以下角色: - **Mediator(抽象中介者)**:声明一个用于与各个同事对象之间交互的接口,通常声明一个注册方法,用于增加同事对象; - **ConcreteMediator(具体中介者)**:实现上面的接口,协调各个同事对象来实现协作行为,维持对各个同事对象的引用; - **Colleague(抽象同事类)**:声明各个同事类公有的接口,同时维持了一个对抽象中介者类的引用; - **ConcreteColleague(具体同事类)**: 具体实现接口,具体同事类只需与中介者通信,通过中介者完成与其他同事类的通信。 **中介者模式的核心在于引入了中介者类**,中介者类承担了两个层次的职责: - 结构上起**中转作用**:通过中介者的中转,各个同事之间不必再相互显示调用或引用,只需通过中介者实现间接调用的目的; - 行为上起**协调作用**:中介者可以进一步地将同事之间的关系进行封装,同事可以一致地和中介者进行交互,而不必指出中介者具体该如何操作,中介者根据封装在自身内部的协调逻辑对同事的请求进一步处理,将同事成员之间的关系行为进行分离和封装。 ## 3.中介者模式代码实例 本节Jungle将采用中介者模式模拟“租客——房租中介——房东”之间的爱恨情仇! ``` Jungle和贱萌兔想要通过房屋中介(Agency)租房,需要去中介处了解房东(Landlord)的信息(姓名,价格,地址和联系方式);房东们(Landlord)需要在中介处注册自己的房源,同时也可以从中介处了解租客(Tenant)的信息(姓名)。 ``` 本例的UML图如下: ![avatar](https://github.com/FengJungle/DesignPattern/blob/master/18.MediatorPattern/1.Picture/%E4%B8%AD%E4%BB%8B%E8%80%85%E6%A8%A1%E5%BC%8F%E5%AE%9E%E4%BE%8BUML%E5%9B%BE.png) ### 3.0.公共头文件 为区分房东和租客,Jungle定义了一个枚举类型和对应的setter、getter方法: ``` #ifndef __COMMON_H__ #define __COMMON_H__ // 公共头文件 #include using namespace std; enum PERSON_TYPE { NONE_PERSON, LANDLORD, TENANT }; #endif //__COMMON_H__ ``` ### 3.1.中介者 #### 3.1.1.抽象中介者 ``` // 抽象中介者 class Mediator { public: Mediator(){} virtual ~Mediator(){} // 声明抽象方法 virtual void operation(Colleague*) = 0; // 声明注册方法 virtual void registerMethod(Colleague*) = 0; }; ``` #### 3.1.2.具体中介者Agency 具体中介者就是真实的中介对象类,他手里有房东的名单(landlordList)和租客名单(tenantList),房东和租客通过registerMethod()在中介处登记注册。同时,房东可以询问中介租客信息,租客也可以向中介询问房东信息。 ``` // 具体中介者 class Agency:public Mediator { public: Agency(){} void registerMethod(Colleague* person){ switch (person->getPersonType()){ case LANDLORD: landlordList.push_back((Landlord*)person); break; case TENANT: tenantList.push_back((Tenant*)person); break; default: printf("wrong person\n"); } } void operation(Colleague* person){ switch (person->getPersonType()){ case LANDLORD: for (int i = 0; i < tenantList.size(); i++){ tenantList[i]->answer(); } break; case TENANT: for (int i = 0; i < landlordList.size(); i++){ landlordList[i]->answer(); } break; default: break; } } private: vectorlandlordList; vectortenantList; }; ``` ### 3.2.同事类 #### 3.2.1.抽象同事类 ``` #include "common.h" using namespace std; // 前向声明 class Mediator; class Agency; // 抽象同事类 class Colleague { public: Colleague(){} virtual ~Colleague(){} void setMediator(Mediator* iMediator){ this->mediator = iMediator; } Mediator* getMediator(){ return this->mediator; } void setPersonType(PERSON_TYPE iPersonType){ this->personType = iPersonType; } PERSON_TYPE getPersonType(){ return this->personType; } virtual void ask() = 0; virtual void answer() = 0; private: PERSON_TYPE personType; Mediator* mediator; }; ``` #### 具体同事类——房东(Landlord) 声明: ``` // 具体同事类:房东 class Landlord :public Colleague { public: Landlord(); Landlord(string iName, int iPrice, string iAddress, string iPhoneNum); void ask(); void answer(); private: string name; int price; string address; string phoneNumber; }; ``` 实现: ``` #include "Colleague.h" #include "Mediator.h" Landlord::Landlord(){ name = "none"; price = 0; address = "none"; phoneNumber = "none"; setPersonType(NONE_PERSON); } Landlord::Landlord(string iName, int iPrice, string iAddress, string iPhoneNum){ name = iName; price = iPrice; address = iAddress; phoneNumber = iPhoneNum; setPersonType(LANDLORD); } void Landlord::answer(){ printf("房东姓名:%s, 房租:%d, 地址:%s, 联系电话:%s\n", name.c_str(), price, address.c_str(), phoneNumber.c_str()); } void Landlord::ask(){ printf("房东%s查看租客信息:\n",name.c_str()); (this->getMediator())->operation(this); } ``` #### 3.2.3.具体同事类——租客(Tenant) 声明: ``` // 具体同事类:租客 class Tenant :public Colleague { public: Tenant(); Tenant(string name); void ask(); void answer(); private: string name; }; ``` 实现: ``` #include "Colleague.h" #include "Mediator.h" Tenant::Tenant(){ name = "none"; setPersonType(NONE_PERSON); } Tenant::Tenant(string iName){ name = iName; setPersonType(TENANT); } void Tenant::ask(){ printf("租客%s询问房东信息\n", name.c_str()); (this->getMediator())->operation(this); } void Tenant::answer(){ printf("租客姓名:%s\n", name.c_str()); } ``` ### 3.3.客户端代码示例及效果 ``` #include #include "Mediator.h" #include "Colleague.h" int main() { // 创建租房中介 Agency *mediator = new Agency(); // 创建3位房东 Landlord *fangdong1 = new Landlord("刘备", 1350, "成都市双流区", "1351025"); Landlord *fangdong2 = new Landlord("关羽", 1500, "成都市武侯区", "1378390"); Landlord *fangdong3 = new Landlord("张飞", 1000, "成都市龙泉驿", "1881166"); fangdong1->setMediator(mediator); fangdong2->setMediator(mediator); fangdong3->setMediator(mediator); // 房东在中介处登记注册房源信息 mediator->registerMethod(fangdong1); mediator->registerMethod(fangdong2); mediator->registerMethod(fangdong3); // 创建两位租客Jungle和贱萌兔 Tenant *jungle = new Tenant("Jungle"); Tenant *jianmengtu = new Tenant("������"); jungle->setMediator(mediator); jianmengtu->setMediator(mediator); // Jungle和贱萌兔在中介处登记求租信息 mediator->registerMethod(jungle); mediator->registerMethod(jianmengtu); jungle->ask(); printf("\n\n"); fangdong1->ask(); printf("\n\n"); system("pause"); delete mediator; delete fangdong1; delete fangdong2; delete fangdong3; delete jungle; delete jianmengtu; mediator = nullptr; fangdong1 = nullptr; fangdong2 = nullptr; fangdong3 = nullptr; jungle = nullptr; jianmengtu = nullptr; return 0; } ``` 运行结果如下: ![avatar](https://github.com/FengJungle/DesignPattern/blob/master/18.MediatorPattern/1.Picture/%E8%BF%90%E8%A1%8C%E5%9B%BE1.png) ## 4.总结 - 优点: - 简化了对象之间的交互,通过中介者,对象之间的多对多关系就简化了相对更简单的一对多关系; - 可将各个同事对象解耦,利于各个同事之间的松散耦合,可独立地改变和复用每一个同事对象,增加新的中介者和同事都比较方便,符合开闭原则; - 可减少子类生成,将原本分布于多个对象之间的行为封装在一起,只需生成新的具体中介者类就可以改变这些行为。 - 缺点: - 具体中介者类中包含了大量与同事之间交互的细节和逻辑,可能使得中介者类很复杂以至于难以管理维护。 - 适用环境: - 系统中的对象之间存在复杂的交互关系,使得系统内逻辑错综复杂,难以管理; - 一个对象引用了其他很多对象,并直接和这些对象交互,导致该对象难以复用。