在面向对象系统的设计和开发过程中,对象之间的交互和通信是最为常见的情况,因为对象间的交互本身就是一种通信。在系统比较小的时候,可能对象间的通信不是很多、对象也比较少,我们可以直接硬编码到各个对象的方法中。但是当系统规模变大,对象的量变引起系统复杂度的急剧增加,对象间的通信也变得越来越复杂,这时候我们就要提供一个专门处理对象间交互和通信的类,这个中介者就是 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.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.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"); }
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.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.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.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种设计模式解析》