您的位置:首页 > 其它

设计模式学习笔记--中介者模式

2016-05-09 18:43 351 查看

一.简介

今天来学习一下传说中的中介者模式。说到中介者,我们最容易想到的就是电话中继器,这里我们看看电话的演变过程吧。最早的电话只是两个通话的用户之间相连,这样的结构简单直接,操作最方便。但是随着使用电话的人数多了起来,为每两部电话之间架设一条线路很明显是不可能的,于是就有了电话中继器,记得以前经常看老电影里面,打电话的人要拿起电话,先打给接线员,说“给我接到XXX那”。没错,接线员就相当于中介者。在面向对象设计中,我们经常有很多类对象,对象之间需要交互,而如果对象过多,而每个对象之间都有可能交互的话,最简单的方式就是每个对象保存其他所有可能交互对象的引用,但是这样做有几个问题,第一,需要保存的内容过多,每个对象存一份,很明显是冗余,对象之间的耦合性太高,牵一发而动全身,如果新增一个类,所有之前的类都要修改。为了解决这个问题,中介者模式就应运而生了。
下面看一下中介者模式的定义以及UML类图:
中介者模式(Mediator Pattern):用一个中介对象(中介者)来封装一系列的对象交互,中介者使各对象不需要显式地相互引用,从而使其耦合松散,而且可以独立地改变它们之间的交互。中介者模式又称为调停者模式,它是一种对象行为型模式。



简单解释一下UML类图,我们原本的对象在图中就相当于Colleague同事类,如果没有用中介者模式,他们每个具体的Collegue都需要保存其他所有对象的引用,UML图会灰常凌乱,而通过中介者Mediator,只有中介者自己保存所有对象的引用,而每个具体的同事类只需要和中介者建立关系,就可以和所有的其他同事类对象进行通信,这样大大降低了系统的耦合度。



二.中介者模式的例子

我们就拿电话的例子来看一下,有中介者和没有中介者的情况。



1.没有使用中介者模式的情况

// Design Pattern.cpp : Defines the entry point for the console application.
//

#include "stdafx.h"
#include <iostream>
#include <string>
#include <vector>
using namespace std;

//抽象电话类
class BasePhone
{
public:
virtual void Call(int num) = 0;
virtual void Answer() = 0;
};

//移动电话
class MobilePhone : public BasePhone
{
private:
vector<BasePhone*> m_phoneVec;
string m_Name;
public:

MobilePhone(string name)
: m_Name(name)
{

}
//添加通讯录,或者说铺电话线更恰当
void Add(BasePhone* phone)
{
m_phoneVec.push_back(phone);
}

//根据号码打电话
virtual void Call(int num) override
{
cout << m_Name << "用手机打电话, ";
m_phoneVec[num]->Answer();
}

//接电话
virtual void Answer() override
{
cout << m_Name << "用手机接电话" << endl;
}
};

class TelePhone : public BasePhone
{
private:
vector<BasePhone*> m_phoneVec;
string m_Name;
public:
TelePhone(string name)
: m_Name(name)
{

}

//添加通讯录,或者说铺电话线更恰当
void Add(BasePhone* phone)
{
m_phoneVec.push_back(phone);
}

//根据号码打电话
virtual void Call(int num) override
{
cout << m_Name << "用座机打电话, ";
m_phoneVec[num]->Answer();
//这里直接根据基类来处理了,如果有其他处理,耦合性更大
}

//接电话
virtual void Answer() override
{
cout << m_Name << "用座机接电话" << endl;
}
};

int _tmain(int argc, _TCHAR* argv[])
{

MobilePhone* phoneA = new MobilePhone("小明");
TelePhone*   phoneB = new TelePhone("小刚");
MobilePhone* phoneC = new MobilePhone("小蔡");

//为每个对象和每个对象之间都建立联系
phoneA->Add(phoneA);
phoneA->Add(phoneB);
phoneA->Add(phoneC);
phoneB->Add(phoneA);
phoneB->Add(phoneB);
phoneB->Add(phoneC);
phoneC->Add(phoneA);
phoneC->Add(phoneB);
phoneC->Add(phoneC);
phoneA->Call(1);
phoneB->Call(2);
phoneC->Call(0);

system("pause");

return 0;
}
结果:
小明用手机打电话, 小刚用座机接电话

小刚用座机打电话, 小蔡用手机接电话

小蔡用手机打电话, 小明用手机接电话

请按任意键继续. . .

2.使用了中介者模式的情况

我们发现,每个电话都要与其他两个电话耦合,虽然这里我使用的是基类,可以降低一部分耦合,但是还是感觉代码不够优雅,我们不希望它们彼此之间联系过于密切,于是我们就添加一个中介者。
// Design Pattern.cpp : Defines the entry point for the console application.
//

#include "stdafx.h"
#include <iostream>
#include <string>
#include <vector>
using namespace std;

class BasePhone;
//中介者基类
class BaseMediator
{
public:
virtual void Call(int num) = 0;
virtual void Add(BasePhone* phone) = 0;
};

//抽象电话类
class BasePhone
{
protected:
BaseMediator* m_Mediator;
public:
//现在我只需要增加一个中介者就可以了
void SetMediator(BaseMediator* mediator)
{
m_Mediator = mediator;
}

//通过中介者向其他电话发送信息
virtual void Call(int num)
{
m_Mediator->Call(num);
}

virtual void Answer() = 0;
};

//电子电话中继器
class ElectricMediator : public BaseMediator
{
private:
vector<BasePhone*> phoneVec;
public:
//登记电话
void Add(BasePhone* phone) override
{
phoneVec.push_back(phone);
}

//拨号
virtual void Call(int num) override
{
phoneVec[num]->Answer();
}
};

//移动电话
class MobilePhone : public BasePhone
{
private:

string m_Name;
public:

MobilePhone(string name)
: m_Name(name)
{

}

//根据号码打电话
virtual void Call(int num) override
{
cout << m_Name << "用手机打电话, ";
BasePhone::Call(num);
}

//接电话
virtual void Answer() override
{
cout << m_Name << "用手机接电话" << endl;
}
};

class TelePhone : public BasePhone
{
private:
string m_Name;
public:
TelePhone(string name)
: m_Name(name)
{

}

//根据号码打电话
virtual void Call(int num) override
{
cout << m_Name << "用座机打电话, ";
BasePhone::Call(num);
}

//接电话
virtual void Answer() override
{
cout << m_Name << "用座机接电话" << endl;
}
};

int _tmain(int argc, _TCHAR* argv[])
{

MobilePhone* phoneA = new MobilePhone("小明");
TelePhone*   phoneB = new TelePhone("小刚");
MobilePhone* phoneC = new MobilePhone("小蔡");
BaseMediator* mediator = new ElectricMediator();

//向中介者中注册电话
mediator->Add(phoneA);
mediator->Add(phoneB);
mediator->Add(phoneC);

//电话只保存中介者的引用就可以了
phoneA->SetMediator(mediator);
phoneB->SetMediator(mediator);
phoneC->SetMediator(mediator);

phoneA->Call(1);
phoneB->Call(2);
phoneC->Call(0);

system("pause");

return 0;
}
结果:
小明用手机打电话, 小刚用座机接电话

小刚用座机打电话, 小蔡用手机接电话

小蔡用手机打电话, 小明用手机接电话

请按任意键继续. .
.



三.中介者模式的总结

最后,我们来看一下中介者模式的优点,缺点以及使用时机:

优点;

1)去除原来同事对象多对多的交互关系,用中介者和对象的一对多的关系代替,原来的网状结构被星型结构所代替。
2)中介者模式将复杂对象之间的耦合关系解除,新增对象时不需要更改原有代码,符合开放-封闭原则。

缺点:
中介者模式将大量对象的交互细节放在中介者中,中介者职责过重,难以维护。

使用时机:
当我们的系统中对象之间的引用关系呈网状,对象之间都需要相互引用,每个对象都需要引用其他对象时,我们就可以考虑使用中介者模式来重构系统。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: