参考:
design-patterns-cpp/Mediator.cpp at master · JakubVojvoda/design-patterns-cpp · GitHubhttps://github.com/JakubVojvoda/design-patterns-cpp/blob/master/command/Command.cpp)
2. 中介者模式 — Graphic Design Patterns (design-patterns.readthedocs.io)
一、什么是中介者模式?
中介者模式定义:用一个中介对象来封装一系列的对象交互,中介者使各对象不需要显式地相互引用,从而使其耦合松散,而且可以独立地改变它们之间的交互。中介者模式又称为调停者模式,它是一种对象行为型模式。
对于一个模块,可能由很多对象构成,而且这些对象之间可能存在相互的引用,为了减少对象两两之间复杂的引用关系,使之成为一个松耦合的系统,我们需要使用中介者模式,这就是中介者模式的模式动机。
如房屋买卖,有了中介的出现,不需要买家与卖家之间有任何联系也能实现交易。
二、实现
中介者(Mediator)模式包含以下主要角色:
1、抽象中介者(Mediator):接口声明了与组件交流的方法,但通常仅包括一个通知方法。组件可将任意上下文(包括自己的对象)作为该方法的参数,只有这样接收组件和发送者类之间才不会耦合。
2、具体中介者(Concrete Mediator):封装了多种组件间的关系。具体中介者通常会保存所有组件的引用并对其进行管理,甚至有时会对其生命周期进行管理。
3、抽象同事类(Colleague):是各种包含业务逻辑的类。每个同事都有一个指向中介者的引用,该引用被声明为中介者接口类型。同事不知道中介者实际所属的类,因此你可通过将其连接到不同的中介者以使其能在其他程序中复用。
4、具体同事类(Concrete Colleague):同事并不知道其他同事的情况。如果同事有重要事件通知,他只能通知中介者。中介者收到通知后能轻易地确定发送者,这或许已足以判断接下来需要接收的同事了。
/*
* C++ Design Patterns: Mediator
* Author: Jakub Vojvoda [github.com/JakubVojvoda]
* 2016
*
* Source code is licensed under MIT License
* (for more details see LICENSE)
*
*/
#include <iostream>
#include <vector>
#include <string>
class Mediator;
/*
* 同事类
* 当他需要与其它同事交流时,需要通过中介者才能发送消息
*/
class Colleague
{
public:
Colleague( Mediator* const m, const unsigned int i ) :
mediator( m ), id( i ) {}
virtual ~Colleague() {}
unsigned int getID()
{
return id;
}
virtual void send( std::string ) = 0;
virtual void receive( std::string ) = 0;
protected:
Mediator *mediator;
unsigned int id;
};
class ConcreteColleague : public Colleague
{
public:
ConcreteColleague( Mediator* const m, const unsigned int i ) :
Colleague( m, i ) {}
~ConcreteColleague() {}
void send( std::string msg );
void receive( std::string msg )
{
std::cout << "Message '" << msg << "' received by Colleague " << id << std::endl;
}
};
/*
* 中介者接口类
* 定义所有同事类通信的接口。
*/
class Mediator
{
public:
virtual ~Mediator() {}
virtual void add( Colleague* const c ) = 0;
virtual void distribute( Colleague* const sender, std::string msg ) = 0;
protected:
Mediator() {}
};
/*
* 具体中介者
* 实现某已知同事之间的沟通方式
*/
class ConcreteMediator : public Mediator
{
public:
~ConcreteMediator()
{
for ( unsigned int i = 0; i < colleagues.size(); i++ )
{
delete colleagues[ i ];
}
colleagues.clear();
}
void add( Colleague* const c )
{
colleagues.push_back( c );
}
void distribute( Colleague* const sender, std::string msg )
{
for ( unsigned int i = 0; i < colleagues.size(); i++ )
{
if ( colleagues.at( i )->getID() != sender->getID() )
{
colleagues.at( i )->receive( msg );
}
}
}
private:
std::vector<Colleague*> colleagues;
};
void ConcreteColleague::send( std::string msg )
{
std::cout << "Message '"<< msg << "' sent by Colleague " << id << std::endl;
mediator->distribute( this, msg );
}
int main()
{
Mediator *mediator = new ConcreteMediator();
Colleague *c1 = new ConcreteColleague( mediator, 1 );
Colleague *c2 = new ConcreteColleague( mediator, 2 );
Colleague *c3 = new ConcreteColleague( mediator, 3 );
mediator->add( c1 );
mediator->add( c2 );
mediator->add( c3 );
c1->send( "Hi!" );
c3->send( "Hello!" );
delete mediator;
return 0;
}
三、优缺点
优点
- 简化了对象之间的交互。
- 将各同事解耦。
- 减少子类生成。
- 可以简化各同事类的设计和实现。
缺点
- 在具体中介者类中包含了同事之间的交互细节,可能会导致具体中介者类非常复杂,使得系统难以维护。
四、适用环境
- 系统中对象之间存在复杂的引用关系,产生的相互依赖关系结构混乱且难以理解。
- 一个对象由于引用了其他很多对象并且直接和这些对象通信,导致难以复用该对象。
- 想通过一个中间类来封装多个类中的行为,而又不想生成太多的子类。可以通过引入中介者类来实现,在中介者中定义对象。
- 交互的公共行为,如果需要改变行为则可以增加新的中介者类。
五、模式应用
MVC架构中控制器,Controller作为一种中介者,它负责控制视图对象View和模型对象Model之间的交互。如在Struts中,Action就可以作为JSP页面与业务对象之间的中介者。
六、模式扩展
- 中介者模式可以方便地应用于图形界面(GUI)开发中,在比较复杂的界面中可能存在多个界面组件之间的交互关系。
- 对于这些复杂的交互关系,有时候我们可以引入一个中介者类,将这些交互的组件作为具体的同事类,将它们之间的引用和控制关系交由中介者负责,在一定程度上简化系统的交互,这也是中介者模式的常见应用之一。