Published on

设计模式(17)——中介者

Authors
  • avatar
    Name
    Leon
    Twitter

十七、Mediator(中介者模式,对象行为型模式)

1. 意图:

  用一个中介对象来封装一系列的对象交互。中介者使各对象不需要显式地相互引用,从而使其耦合松散而且可以独立地改变它们之间的交互。

2. 动机:

  面向对象设计鼓励将行为分布到各个对象中。这种分布可能会导致对象间有许多连接。在最坏的情况下,每一个对象都知道其他所有对象。   虽然将一个系统分割成许多对象通常可以增加可复用性,但是对象间相互连接的激增又会降低其可复用性。大量的相互连接使得一个对象似乎不太可能在没有其他对象的支持下工作——系统表现为一个不可分割的整体。而且,对系统的行为进行任何较大的改动都 十分困难,因为行为被分布在许多对象中。结果是,你可能不得不定义很多子类以定制系统的行为。

3. 适用:

  1. 一组对象以定义良好但是复杂的方式进行通信。产生的相互依赖关系结构混乱且难以理解。
  2. 一个对象引用其他很多对象并且直接与这些对象通信,导致难以复用该对象。
  3. 想定制一个分布在多个类中的行为,而又不想生成太多的子类。

4. 类图:

5. Facade 与 Mediator

  Facade 与 Mediator 的不同之处在于它是对一个对象子系统进行抽象,从而提供了一个更为方便的接口。它的协议是单向的,即 Facade 对象对这个子系统类提出请求,但反之则不行。相反,Mediator 提供了各 Colleague 对象不支持或不能支持的协作行为,而且协议是多向的。

6. 思考:

  中介者用来集中对象之间复杂的沟通和控制方式。现实中的交换机就类似中介者模式,如果一台电脑需要加入局域网与其它电脑通信,不需要与其它每台电脑单独建立连接,只需要与交换机连接即可,交换机会帮忙处理新电脑与其它电脑的连接。

7. C++实现:

  1. 编写一个中介类接口 Mediator,中介类 ConcreteMediator,含有一些对象间的交互方法如 DoActionFromAtoB()DoActionFromBtoA()
  2. 编写一个同事类接口 Colleague,同事类 ConcreteColleague,包含交互方法 Action(),方法体调用中介的交互方法 DoActionFromAtoB()DoActionFromBtoA()
  3. 中介类编写一个引入对象的方法 IntroColleague()
  4. Colleague has-a 中介类对象 _mdt,通过同事类的构造函数初始化

Mediator.h

//Mediator.h
#pragma once

class Colleague;

class Mediator {
public:
	virtual ~Mediator();
	virtual void DoActionFromAtoB() = 0;
	virtual void DoActionFromBtoA() = 0;
protected:
	Mediator();
private:
};

class ConcreteMediator : public Mediator {
public:
	ConcreteMediator();
	ConcreteMediator(Colleague* clgA, Colleague* clgB);
	~ConcreteMediator();
	void SetConcreteColleageA(Colleague* clgA);
	void SetConcreteColleageB(Colleague* clgB);
	Colleague* GetConcreteColleagueA();
	Colleague* GetConcreteColleagueB();
	void IntroColleague(Colleague* clgA, Colleague* clgB);
	void DoActionFromAtoB();
	void DoActionFromBtoA();
protected:
private:
	Colleague* _clgA;
	Colleague* _clgB;
};

Mediator.cpp

//Mediator.cpp
#include "Mediator.h"
#include "Colleague.h"

Mediator::Mediator() {}
Mediator::~Mediator(){}

ConcreteMediator::ConcreteMediator() {}
ConcreteMediator::ConcreteMediator(Colleague* clgA, Colleague* clgB){
	this->_clgA = clgA;
	this->_clgB = clgB;
}
ConcreteMediator::~ConcreteMediator() {}

void ConcreteMediator::SetConcreteColleageA(Colleague * clgA){
	this->_clgA = clgA;
}

void ConcreteMediator::SetConcreteColleageB(Colleague * clgB){
	this->_clgB = clgB;
}

Colleague * ConcreteMediator::GetConcreteColleagueA(){
	return _clgA;
}

Colleague * ConcreteMediator::GetConcreteColleagueB(){
	return _clgB;
}

void ConcreteMediator::IntroColleague(Colleague * clgA, Colleague * clgB){
	this->_clgA = clgA;
	this->_clgB = clgB;
}

void ConcreteMediator::DoActionFromAtoB() {
	_clgB->SetState(_clgA->GetState());
}
void ConcreteMediator::DoActionFromBtoA() {
	_clgA->SetState(_clgB->GetState());
}

Colleague.h

//Colleague.h
#pragma once

#include <string>
using namespace::std;

class Mediator;

class Colleague {
public:
	virtual ~Colleague();
	virtual void Action() = 0;
	virtual void SetState(const string& sdt) = 0;
	virtual string GetState() = 0;
protected:
	Colleague();
	Colleague(Mediator* mdt);
	Mediator* _mdt;
private:
};

class ConcreteColleagueA : public Colleague {
public:
	ConcreteColleagueA();
	ConcreteColleagueA(Mediator* mdt);
	~ConcreteColleagueA();
	void Action();
	void SetState(const string& sdt);
	string GetState();
protected:
private:
	string _sdt;
};

class ConcreteColleagueB : public Colleague {
public:
	ConcreteColleagueB();
	ConcreteColleagueB(Mediator* mdt);
	~ConcreteColleagueB();
	void Action();
	void SetState(const string& sdt);
	string GetState();
protected:
private:
	string _sdt;
};

Colleague.cpp

//Colleague.cpp

#include "Colleague.h"
#include "Mediator.h"

#include <iostream>
using namespace ::std;

Colleague::Colleague() {}
Colleague::Colleague(Mediator* mdt) {
	this->_mdt = mdt;
}
Colleague::~Colleague() {}

ConcreteColleagueA::ConcreteColleagueA() {}
ConcreteColleagueA::ConcreteColleagueA(Mediator* mdt) : Colleague(mdt) {}
ConcreteColleagueA::~ConcreteColleagueA() {}

void ConcreteColleagueA::Action(){
	_mdt->DoActionFromAtoB();
	cout << "State of ConcreteColleagueB: " << this->GetState() << endl;
}

void ConcreteColleagueA::SetState(const string& sdt) {
	_sdt = sdt;
}
string ConcreteColleagueA::GetState() {
	return _sdt;
}

ConcreteColleagueB::ConcreteColleagueB(){}

ConcreteColleagueB::ConcreteColleagueB(Mediator * mdt) : Colleague(mdt){}

ConcreteColleagueB::~ConcreteColleagueB(){}

void ConcreteColleagueB::Action(){
	_mdt->DoActionFromBtoA();
	cout << "State of ConcreteColleagueB: " << this->GetState() << endl;
}

void ConcreteColleagueB::SetState(const string & sdt){
	this->_sdt = sdt;
}

string ConcreteColleagueB::GetState(){
	return _sdt;
}

main.cpp

//main.cpp
#include "Mediator.h"
#include "Colleague.h"

#include <iostream>
using namespace::std;

int main(int argc, char* argv[]) {
	ConcreteMediator* m = new ConcreteMediator();
	ConcreteColleagueA* c1 = new ConcreteColleagueA(m);
	ConcreteColleagueB* c2 = new ConcreteColleagueB(m);

	m->IntroColleague(c1, c2);

	c1->SetState("old");
	c2->SetState("old");
	c1->Action();
	c2->Action();
	cout << endl;

	c1->SetState("new");
	c1->Action();
	c2->Action();
	cout << endl;

	c2->SetState("old");
	c2->Action();
	c1->Action();

	return 0;

}