中介者模式
用一个中介对象来封装一系列对象的交互,从而把一批原来可能是交互关系复杂的对象转换成一组松散耦合的中间对象,以有利于维护和修改。 --百度百科
中介者模式是将多对多的交互关系转化为一对多。软件中设计一个中介对象专门管理交互逻辑,如此一来便能够将各个对象间错综复杂的耦合统一到与中介对象耦合。
适用中介者模式的场景
当多个组件或对象互相依赖,动一发而牵全身。
该模式能够使各个组件相互独立,互不耦合,从而保证各个组件的修改互不牵连。当某些组件因为依赖其他组件,而无法复用时。
采用中介者将组件间的依赖仅面向中介者。当需要在不同场景复用基本行为,导致被迫产生大量组件子类。
由于所有组件间关系都被包含在中介者中, 因此你无需修改组件就能方便地新建中介者类以定义新的组件合作方式
典型案例
典型的租房案例。租房中介整合多个房东的房源,用户只需要从中介这里找到适合自己的房源即可。租房中介便将房东与用户的交互管理起来,多个房东和用户都只需与租房中介交互。
-
机场塔台场景。飞机在降落前需要提前了解降落方位,因此需要了解其他飞机的降落位置,从而获取到空闲的降落位置。每个飞机之间都要建立联系。
飞机之间交互
从图上看,飞机之间关系相当复杂。降落飞机需要向所有的飞机发送请求信息并等待应答,效率低下。
为提高效率,引入塔台角色。塔台事先与其他飞机交互保存各个飞机的信息,当有飞机发送降落请求时,塔台根据保存的信息应答降落请求即可。如此一来,大大提升了交互效率。
![](https://i-blog.csdnimg.cn/blog_migrate/63a13323f19db9424917f3fc226153d9.png)
中介者模式UML类图
这里以塔台案例为案例绘制UML类图。
![](https://i-blog.csdnimg.cn/blog_migrate/5e670c9c472b5abcde3e45a9f6dfa539.png)
- CToWerBase: 塔台抽象类。
- CChengduTower: 具体的塔台类,扮演中介者角色,与各个飞机交互。
- CAirPlane: 飞机抽象类。
- CAirBusA319、CBoeing737、CComacC919:具体的飞机类,只与塔台对象发生交互。
源码实现
本源码只实现了塔台与飞机间的交互框架,具体的飞机停靠业务逻辑没有体现。
客户端代码
int main(int argc, char *argv[])
{
CChengduTowerMediator *theChengduTower = CChengduTowerMediator::GetInstance();
CAirBusA319 *theAirBus319 = new CAirBusA319();
theAirBus319->SetMediator(theChengduTower);
CBoeing737 *theBoeing737 = new CBoeing737();
theBoeing737->SetMediator(theChengduTower);
CComacC919 *theCComacC919 = new CComacC919();
theCComacC919->SetMediator(theChengduTower);
// 塔台向所有飞机广播,通报姓名
//MAIN_LOGI("--> Tower Radio: notify name\n");
theChengduTower->NotifyObserverAll((char *)"Please notify your name");
MAIN_LOG("\n");
// AirBus319应答塔台
//MAIN_LOGI("--> AirBus319 Notify\n");
theAirBus319->Notify((char *)"This is AirBus319");
MAIN_LOG("\n");
// theBoeing737应答塔台
//MAIN_LOGI("--> Boeing737 Notify\n");
theBoeing737->Notify((char *)"This is Boeing737");
MAIN_LOG("\n");
// CComacC919应答塔台
//MAIN_LOGI("--> CComacC919 Notify\n");
theCComacC919->Notify((char *)"This is CComacC919");
MAIN_LOG("\n");
delete theAirBus319;
delete theBoeing737;
delete theCComacC919;
return 0;
}
执行效果
$ ./exe
[CAirBusA319] Recv: Please notify your name
[CBoeing737] Recv: Please notify your name
[CComacC919] Recv: Please notify your name
Tower Recv: [0] This is AirBus319
[CAirBusA319] Recv: Ack
Tower Recv: [1] This is Boeing737
[CBoeing737] Recv: Ack
Tower Recv: [2] This is CComacC919
[CComacC919] Recv: Ack
塔台接口
class CChengduTowerMediator : public CTowerMediatorBase
{
public:
CChengduTowerMediator();
~CChengduTowerMediator();
static CChengduTowerMediator* GetInstance();
// 注册飞机实例
int Register(CAirplaneBase* airplane);
// 注销指定飞机ID
int UnRegister(int RegisterId);
// 向指定飞机发送消息
int SendMsg(int RegisterId, void *msg);
// 向所有注册飞机发送广播
int NotifyObserverAll(void *msg);
// 接收飞机消息
int Receive(int id, void *msg);
private:
// 飞机注册表
std::map<int, CAirplaneBase*> mAirplaneHashTable;
};
飞机接口
class CAirBusA319 : public CAirplaneBase
{
public:
CAirBusA319();
~CAirBusA319();
void SetMediator(CTowerMediatorBase *meditor);
int Notify(void *msg);
int Receive(void *msg);
private:
int mIdForMediator;
CTowerMediatorBase *pmMeditor;
};
总结
中介模式的实现不是太复杂,主要引进一个“中介”角色,将各个组件的交互全部转移到与“中介”交互中来。设计思想,便是将多对多杂乱无章的交互关系,梳理为一对多有序的交互。
中介者模式的思想主要为尽量减少各个组件之间的耦合关系,将复杂的多对多耦合关系转化为中介者对各个组件一对多的耦合关系。
中介者模式解除了各个组件之间的耦合,使其相对独立。自身改动不会影响其他组件代码的修改,同时顾忌其他组件的变化带来的影响。满足单一原则,更易维护。
在软件的设计中,大都是多个设计模式搭配使用的,本篇实现不仅包含中介者模式还有观察者模式的体现。因此在面对具体的场景时,只根据其组件特性选择对应的一种或多种设计模式即可。