DesignPattern/18.MediatorPattern/18.MediatorPattern.md

310 lines
10 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

# 中介者模式,说一说贝壳找房
![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 <vector>
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:
vector<Landlord*>landlordList;
vector<Tenant*>tenantList;
};
```
### 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 <iostream>
#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("<22><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>");
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.总结
- 优点:
- 简化了对象之间的交互,通过中介者,对象之间的多对多关系就简化了相对更简单的一对多关系;
- 可将各个同事对象解耦,利于各个同事之间的松散耦合,可独立地改变和复用每一个同事对象,增加新的中介者和同事都比较方便,符合开闭原则;
- 可减少子类生成,将原本分布于多个对象之间的行为封装在一起,只需生成新的具体中介者类就可以改变这些行为。
- 缺点:
- 具体中介者类中包含了大量与同事之间交互的细节和逻辑,可能使得中介者类很复杂以至于难以管理维护。
- 适用环境:
- 系统中的对象之间存在复杂的交互关系,使得系统内逻辑错综复杂,难以管理;
- 一个对象引用了其他很多对象,并直接和这些对象交互,导致该对象难以复用。