(1)中介者模式的本质:封装交互。中介者的目的,就是用来封装多个对象的交互,这些交互的处理多在中介者对象里面实现。只要是实现封装对象之间的交互功能,就可用中介者模式,而不必过于拘泥于中介者模式本身的结构。
(2)需要Mediator接口吗
这取决于是否会提供多个不同的中介者实现。如果中介者实现只有一个的话,而且预计中也没有扩展的需求,那就可以不定义Mediator接口。如果中介者实现不只一个,或者预计有扩展的要求,那么就需要定义Mediator接口。让各个同事类来面向中介者接口编程。
(3)同事关系
在标准的中介者模式中,将使用中介者对象来交互的那些对象称为同事类,在中介者模式中要求这些类都要继承相同的类,也就是说,这些对象从某个角度来讲是同一个类型,算是兄弟对象。
(4)同事和中介者的关系
①当一个同事对象发生了改变,需要主动通知中介者,让中介者去处理与其他同事对象相关的交互。
②同事对象需要知道中介者对象是谁,反过来,中介者对象也需要知道相关的同事对象,这样才能与同事对象进行交互。
③中介者对象与同事对象之间是相互依赖的。
(5)如何实现同事和中介者的通信
①同事类持有中介者对象,可以通过Mediator接口中定义一个特殊的通知接口(如changed),并把this当做参数传入,这样在中介者对象里面,就可以去获取这个同事对象的实例或当中的数据了。中介者对象里面记录着各个同事,会根据从changed接口中传入来的对象,判断下一步的动作。
②另一种实现方式可以采用观察者模式,把Mediator实现成为观察者,而各个同事类实现成为Subject,这样同事类发生了改变,会通知Mediator。Mediator在接到通知的以后,会与相应的同事对象进行交互。
【编程实验】用电脑看电影
//行为模式——中介者模式
//场景:使用电脑来看电影
//中介者:主板
//同事类:CPU、内存、光驱、显卡、声卡等
#include <iostream>
#include <string>
#include <vector>
using namespace std;
class CHardware;//前向声明
//*******************************************抽象中介者**************************************
//抽象中介者
class CAbsMediator{
public:
//同事对象在自身改变的时候调用这个接口来通知中介者
virtual void Changed(CHardware* hardware) = 0;
};
//*******************************************抽象同事类**************************************
//抽象同事类
class CHardware{
protected:
CAbsMediator* pMediator;
public:
CHardware(CAbsMediator* mediator){pMediator = mediator;}
//获取当前同事类对应的中介者对象
CAbsMediator& GetMediator(){return *pMediator;}
};
//具体的同事类:光驱
class CCdDrv : public CHardware{
private:
string strDat;
public:
CCdDrv(CAbsMediator* mediator) : CHardware(mediator){}
void ReadCd(){//读取光盘
//逗号前是视频显示的数据,逗号后是声音
strDat = "设计模式,值得好好研究";
//通知中介者(主板),自己的状态发生了改变
pMediator->Changed(this);
}
string& GetDat(){return strDat;}
};
//具体的同事类:CPU
class CCpu : public CHardware{
private:
string strVideo;//分解出来的视频数据
string strSound;//分解出来的声音数据
public:
CCpu(CAbsMediator* mediator) : CHardware(mediator){}
string& GetVideo(){return strVideo;}
string& GetSound(){return strSound;}
void DispartData(string data){//处理数据,把数据分成音频和视频数据
int iPos = data.find(",");
strVideo = data.substr(0, iPos);
strSound = data.substr(iPos+1, data.length()-iPos);
//通知主板,CPU的工作完成
pMediator->Changed(this);
}
};
//具体的同事类:显卡类
class CVideoCard : public CHardware{
private:
string strVideo;//被显示的数据
public:
CVideoCard(CAbsMediator* mediator) : CHardware(mediator){}
void DispVideo(string data){
cout << "您正在观看的是:" << data << endl;
}
};
//具体的同事类:声卡类
class CSoundCard : public CHardware{
private:
string strSound;//被播放的声音数据
public:
CSoundCard(CAbsMediator* mediator) : CHardware(mediator){}
void DispSound(string data){//显示数据
cout << "画外音:" << data << endl;
}
};
//*************************************具体中介者****************
//主板类
class CMainBoard : CAbsMediator{
private:
CCdDrv* pCdDrv;
CCpu* pCpu;
CVideoCard* pVc;
CSoundCard* pSc;
public:
CMainBoard()
{
pCdDrv = new CCdDrv(this);
pCpu = new CCpu(this);
pVc = new CVideoCard(this);
pSc = new CSoundCard(this);
}
~CMainBoard()
{
delete pCdDrv; pCdDrv = NULL;
delete pCpu; pCpu = NULL;
delete pVc; pVc = NULL;
delete pSc; pSc = NULL;
}
CCdDrv* GetCd(){return pCdDrv;}
//处理光驱读取数据以后与其他对象的交互
void CdDrvReadDat(CCdDrv* cd){
//1.获取光驱读取的数据
string strData = cd->GetDat();
//2.把这些数据传给CPU进行处理
pCpu->DispartData(strData);
}
//CPU处理完数据后与其他对象的交互
void CpuParseDat(CCpu* cpu){
//1.先取出CPU处理后的数据
string strVideo = cpu->GetVideo();
string strSound = cpu->GetSound();
//2. 把数据传递给显卡和声卡展示出来
pVc->DispVideo(strVideo);
pSc->DispSound(strSound);
}
//接收通知
void Changed(CHardware* hardware){
if(hardware == pCdDrv) CdDrvReadDat(pCdDrv);
else if(hardware == pCpu) CpuParseDat(pCpu);
}
};
void WatchFilm()
{
CMainBoard oMainBoard;
//开始看电影,把光盘放入光驱,光驱开始读盘
oMainBoard.GetCd()->ReadCd();
}