一、描述:
在面向对象系统的设计和开发过程中,对象之间的交互和通信是最为常见的情况,因为对象间的交互本身就是一种通信。在系统比较小的时候,可能对象间的通信不是很多、对象也比较少,我们可以直接硬编码到各个对象的方法中。但是当系统规模变大,对象的量变引起系统复杂度的急剧增加,对象间的通信也变得越来越复杂,这时候我们就要提供一个专门处理对象间交互和通信的类,这个中介者就是 Mediator 模式。Mediator 模式提供将对象间的交互和通讯封装在一个类中,各个对象间的通信不必显势去声明和引用,大大降低了系统的复杂性能(了解一个对象总比深入熟悉 n 个对象要好)。另外 Mediator 模式还带来了系统对象间的松耦合,这些将在讨论中详细给出。
Mediator 模式典型的结构图为:
Mediator 模式中,每个 Colleague 维护一个 Mediator,当要进行交互,例如图中ConcreteColleagueA 和 ConcreteColleagueB 之间的交互就可以通过 ConcreteMediator 提供的DoActionFromAtoB 来处理,ConcreteColleagueA 和 ConcreteColleagueB 不必维护对各自的引用,甚至它们也不知道各个的存在。Mediator 通过这种方式将多对多的通信简化为了一(Mediator)对多(Colleague)的通信。
二、实例:
各位好,大家都是来自五湖四海,都要生存,于是都找了个靠山——公司,给你发薪水的地方,那公司就要想尽办法盈利赚钱,盈利方法则不尽相同,但是作为公司都有相同三个环节:采购、销售和库存,这个怎么说呢?比如一个软件公司,要开发软件,需要开发环境吧, Windows 操作系统,数据库产品等,这你得买吧,那就是采购,开发完毕一个产品还要把产品推销出去,推销出去了大家才有钱赚,不推销出去大家都去喝西北风呀,既然有产品就必然有库存,软件产品也有库存,你总要拷贝吧,虽然是不需要占用库房空间,那也是要占用光盘或硬盘,这也是库存,再比如做咨询服务的公司,它要采购什么?采购知识,采购经验,这是这类企业的生存之本,销售的也是知识和经验,库存同样是知识和经验。尽然进销存是这么的重要,我们今天就来讲讲它的原理和设计,我相信很多人都已经开发过这种类型的软件,基本上都形成了固定套路,不管是单机版还是网络版,一般的做法都是通过数据库来完成相关产品的管理,相对来说还是比较简单的项目,三个模块之间的示意图如下:
我们从这个示意图上可以看出,三个模块是相互依赖的,基本上是你中有我,我中有你,为什么呢?我们就以一个终端销售商(什么是终端销售商?就是以服务最终客户为目标的企业,比如 XX 超市,国美电器等等)为例子,比如采购部门要采购 IBM 型号的电脑了,它是根据什么来决定采购的呢?根据两个要素:
销售情况。销售部门要反馈销售情况,畅销就多采购,滞销就不采购;库存情况。即使是畅销产品,库存都有 1000 台了,每天才卖出去 10 台,还要采购吗?!销售模块是企业的盈利核心,也是对其他两个模块有影响的:库存情况。库房有货,才能销售,没货空手套白狼是不行的;督促采购。在特殊情况下,比如一个企业客户一下子要卖 100 台电脑,你库存里自由 80 台,怎么办?
催采购部门赶快采购呀!
同样的,库存管理也对其他两个模块有影响,库房是有容积限制的,不可能无限大,所以就有了清仓处理,那就要求采购部门别采购了,同时销售部门赶快打折销售。
从以上分析来看,这三个模块都是有自己的行为,并且与其他模块之间的行为产生关联关系,就类似我们在办公室中的同事,大家各干各的活,但是彼此之间还是有交叉的,于是乎大家之间就产生紧耦合,也就是一个团队。
我们先来实现这个进销存,先看类图:
Purchase 负责采购管理,buyIBMComputer 是指定了采购 IBM 电脑,refuseBuyIBM 是不再采购 IBM 了 。
你难道就没有发现这三个类间是彼此关联的吗?每个类都与其他两个类产生了关联关系,迪米特法则教育我们“每个类只和朋友类交流”,这个朋友类可不是越多越好,越多耦合性越大,改一个对象而要修改一片对象,这可不是面向对象设计所期望的,而且这还是就三个模块的情况,比较简单的一个小项目,如果有十个八个这样的模块是不是就要歇菜了,我们把进销存扩充一下,如下图的情况:
是不是看到一个蜘蛛网的结构,这个别说是编写程序了,就是给人看估计能让一大批的人昏倒!每个对象都要和其他的几个对象交流,对象越多,每个对象要交流的成本也就越多了,就单独维护这些对象的交流基本上就能让一大批程序员望而却步,这明摆着不是人干的活嘛!从这方面来,我们已经发现设计的缺陷,作为一个架构师,发现缺陷就要想办法来修改,我们思考一下,怎么来修改。
大家都是学计算机的,应该在上学的时候讲过一些网络的基本知识,还记得网络拓扑有几种类型吗?总线型,环型,星型,(什么?想不起来?!惩罚一下自己去),我们来想想星型拓扑是什么什么样子的,如下图:
星型网络拓扑中每个计算机通过交换机和其他计算机进行数据交换,各个计算机之间并没有直接出现交互的情况,结构简单,而且稳定,只要中间那个交换机不瘫痪,整个网络就不会发生大的故障,公司和网吧一般都采用星型网络,那也说明星型拓扑是深得民心,那我们来想想是不是可以把这种星型结构引入到我们的设计中呢?说干就干,我们先画一个示意图:
加入了一个中介者作为三个模块的交流核心,每个模块之间不再相互交流,要交流就通过中介者进行,每个模块只负责自己的业务逻辑,不属于自己的则丢给中介者来处理,看类图:
我的工程目录:
注释:
main(),客户
IAbstractMediator,中介者接口
CMediatorNow,中介者实现类
IAbstractColleague,部门协作接口
CPurchase,采购管理
CSale,销售管理
CStock,存货管理
说明:CMediatorNow来组织IAbstractColleague接口的相互调用关系,客户main()直接访问CMediatorNow的接口进行业务处理。CMediatorNow很好的封装了业务,实现了高内聚。
部门协作接口:IAbstractColleague类
#ifndef Mediator_IAbstractColleague_h
#define Mediator_IAbstractColleague_h
class IAbstractMediator;
class IAbstractColleague
{
public:
IAbstractColleague(IAbstractMediator *pMediator)
{
this->m_pMediator = pMediator;
}
virtual ~IAbstractColleague(void)
{
}
protected:
IAbstractMediator *m_pMediator;
};
#endif
采购管理:CPurchase
CPurchase.h
#ifndef __Mediator__Purchase__
#define __Mediator__Purchase__
#include <iostream>
#include "IAbstractColleague.h"
class IAbstractMediator;
class CPurchase :
public IAbstractColleague
{
public:
CPurchase(IAbstractMediator *pMediator);
~CPurchase(void);
//采购IBM型号的电脑
void BuyIBMComputer(int number);
//不再采购IBM电脑
void RefuseBuyIBM();
};
#endif /* defined(__Mediator__Purchase__) */
CPurchase.cpp
#include "Purchase.h"
#include "IAbstractMediator.h"
using std::cout;
using std::endl;
CPurchase::CPurchase(IAbstractMediator *pMediator) : IAbstractColleague(pMediator)
{
}
CPurchase::~CPurchase(void)
{
}
void CPurchase::BuyIBMComputer( int number )
{
m_pMediator->Execute("purchase.buy", number);
}
void CPurchase::RefuseBuyIBM()
{
cout << "不再采购IBM电脑" << endl;
}
销售管理:CSale类
CSale.h
#ifndef __Mediator__Sale__
#define __Mediator__Sale__
#include <iostream>
#include "IAbstractColleague.h"
class IAbstractMediator;
class CSale :
public IAbstractColleague
{
public:
CSale(IAbstractMediator *pMediator);
~CSale(void);
//销售IBM型号的电脑
void SellIBMComputer(int number);
//反馈销售情况,0——100之间变化,0代表根本就没人卖,100代表非常畅销,出一个卖一个
int GetSaleStatus();
//折价处理
void OffSale();
};
#endif /* defined(__Mediator__Sale__) */
CSale.cpp
#include "Sale.h"
#include "IAbstractMediator.h"
#include "Sale.h"
#include <time.h>
using std::cout;
using std::endl;
CSale::CSale(IAbstractMediator *pMediator) : IAbstractColleague(pMediator)
{
}
CSale::~CSale(void)
{
}
void CSale::SellIBMComputer(int number)
{
m_pMediator->Execute("sale.sell", number);
cout << "销售IBM电脑‘" << number << "台" << endl;
}
int CSale::GetSaleStatus()
{
srand((unsigned int)time(NULL));
int saleStatus = rand() % 100;
cout << "IBM电脑的销售情况为:" << saleStatus << endl;
return saleStatus;
}
void CSale::OffSale()
{
this->IAbstractColleague::m_pMediator->Execute("sale.offsell");
}
存货管理:CStock类
Stock.h
#ifndef __Mediator__Stock__
#define __Mediator__Stock__
#include <iostream>
#include "IAbstractColleague.h"
class CStock :public IAbstractColleague
{
public:
CStock(IAbstractMediator *pMediator);
~CStock(void);
//库存增加
void Increase(int number);
//库存降低
void Decrease(int number);
//获得库存数量
int GetStockNumber();
//存货压力大了,就要通知采购人员不要采购,销售人员要尽快销售
void ClearStock();
private:
static int COMPUTER_NUMBER;
};
#endif /* defined(__Mediator__Stock__) */
Stock.cpp
#include "Stock.h"
#include "IAbstractMediator.h"
using std::cout;
using std::endl;
//刚开始有100台电脑
int CStock::COMPUTER_NUMBER = 100;
CStock::CStock(IAbstractMediator *pMediator) : IAbstractColleague(pMediator)
{
}
CStock::~CStock(void)
{
}
void CStock::Increase(int number)
{
COMPUTER_NUMBER += number;
cout << "库存数量为:" << COMPUTER_NUMBER << endl;
}
void CStock::Decrease(int number)
{
COMPUTER_NUMBER -= number;
cout << "库存数量为:" << COMPUTER_NUMBER << endl;
}
int CStock::GetStockNumber()
{
return COMPUTER_NUMBER;
}
void CStock::ClearStock()
{
cout << "清理存货数量为:" << COMPUTER_NUMBER << endl;
m_pMediator->Execute("stock.clear");
}
中介者接口:IAbstractMediator
IAbstractMediator.h
#ifndef Mediator_IAbstractMediator_h
#define Mediator_IAbstractMediator_h
#include "IAbstractColleague.h"
#include "Purchase.h"
#include "Sale.h"
#include "Stock.h"
#include <iostream>
using std::string;
class IAbstractMediator
{
public:
IAbstractMediator(void)
{
m_pPurchase = new CPurchase(this);
m_pSale = new CSale(this);
m_pStock = new CStock(this);
}
virtual ~IAbstractMediator(void)
{
delete m_pPurchase;
m_pPurchase = NULL;
delete m_pSale;
m_pSale = NULL;
delete m_pStock;
m_pStock = NULL;
}
//中介者最重要的方法,叫做事件方法,处理多个对象之间的关系
virtual void Execute(string str, ...) = 0;
protected:
IAbstractColleague *m_pPurchase;
IAbstractColleague *m_pSale;
IAbstractColleague *m_pStock;
};
#endif
中介者实现类:CMediatorNow
CMediatorNow.h
#ifndef __Mediator__MediatorNow__
#define __Mediator__MediatorNow__
#include <iostream>
#include "IAbstractMediator.h"
class CMediatorNow :
public IAbstractMediator
{
public:
CMediatorNow(void);
~CMediatorNow(void);
void Execute(string str, ...);
private:
//采购电脑
void BuyComputer(int count);
//销售电脑
void SellComputer(int count);
//折价销售
void OffSell();
//清仓处理
void ClearStock();
};
#endif /* defined(__Mediator__MediatorNow__) */
MediatorNow.cpp
#include "MediatorNow.h"
using std::cout;
using std::endl;
CMediatorNow::CMediatorNow(void)
{
}
CMediatorNow::~CMediatorNow(void)
{
}
void CMediatorNow::Execute(string str, ...)
{
va_list arg_ptr;
va_start(arg_ptr, str);
if (str.compare("purchase.buy") == 0)
{
int count = va_arg(arg_ptr, int);
va_end(arg_ptr);
this->BuyComputer(count);
}
else if (str.compare("sale.sell") == 0)
{
int count = va_arg(arg_ptr, int);
va_end(arg_ptr);
this->SellComputer(count);
}
else if (str.compare("sale.offsell") == 0)
{
this->OffSell();
}
else if(str.compare("stock.clear") == 0)
{
this->ClearStock();
}
}
//采购电脑
void CMediatorNow::BuyComputer(int count)
{
int saleStatus = static_cast<CSale*>(m_pSale)->GetSaleStatus();
if (saleStatus > 80)
{
cout << "采购IBM电脑:" << count << "台" << endl;
static_cast<CStock*>(m_pStock)->Increase(count);
}
else
{
int buyNumber = count / 2;
cout << "采购IBM电脑:" << buyNumber << "台" << endl;
static_cast<CStock*>(m_pStock)->Increase(buyNumber);
}
}
//销售电脑
void CMediatorNow::SellComputer(int count)
{
int stockNumber = static_cast<CStock*>(m_pStock)->GetStockNumber();
if (stockNumber < count)
{
static_cast<CPurchase*>(m_pPurchase)->BuyIBMComputer(count);
}
static_cast<CStock*>(m_pStock)->Decrease(count);
}
//折价销售电脑
void CMediatorNow::OffSell()
{
int offCount = static_cast<CStock*>(m_pStock)->GetStockNumber();
cout << "折价销售IBM电脑" << offCount << "台" << endl;
}
void CMediatorNow::ClearStock()
{
static_cast<CSale*>(m_pSale)->OffSale();
static_cast<CPurchase*>(m_pPurchase)->RefuseBuyIBM();
}
客户:main
main.cpp
#include <iostream>
#include "IAbstractMediator.h"
#include "IAbstractColleague.h"
#include "MediatorNow.h"
#include "Purchase.h"
#include "Sale.h"
#include "Stock.h"
using std::cout;
using std::endl;
void DoIt()
{
CMediatorNow mediator;
cout << "----------采购人员采购电脑----------" << endl;
CPurchase purchase(&mediator);
purchase.BuyIBMComputer(100);
cout << "----------销售人员销售电脑----------" << endl;
CSale sale(&mediator);
sale.SellIBMComputer(1);
cout << "----------库房管理人员清库处理----------" << endl;
CStock stock(&mediator);
stock.ClearStock();
}
int main(int argc, const char * argv[])
{
DoIt();
// insert code here...
std::cout << "Hello, World!\n";
return 0;
}
结果如下:
参考文献:《设计模式之禅》,《GoF_23种设计模式解析》