设计方式(c++)笔记之十八(Mediator模式)

设计模式(c++)笔记之十八(Mediator模式)

一、描述:


      在面向对象系统的设计和开发过程中,对象之间的交互和通信是最为常见的情况,因为对象间的交互本身就是一种通信。在系统比较小的时候,可能对象间的通信不是很多、对象也比较少,我们可以直接硬编码到各个对象的方法中。但是当系统规模变大,对象的量变引起系统复杂度的急剧增加,对象间的通信也变得越来越复杂,这时候我们就要提供一个专门处理对象间交互和通信的类,这个中介者就是 Mediator 模式。Mediator 模式提供将对象间的交互和通讯封装在一个类中,各个对象间的通信不必显势去声明和引用,大大降低了系统的复杂性能(了解一个对象总比深入熟悉 n 个对象要好)。另外 Mediator 模式还带来了系统对象间的松耦合,这些将在讨论中详细给出。 


Mediator 模式典型的结构图为: 


设计方式(c++)笔记之十八(Mediator模式)


      Mediator 模式中,每个 Colleague 维护一个 Mediator,当要进行交互,例如图中ConcreteColleagueA 和 ConcreteColleagueB 之间的交互就可以通过 ConcreteMediator 提供的DoActionFromAtoB 来处理,ConcreteColleagueA 和 ConcreteColleagueB 不必维护对各自的引用,甚至它们也不知道各个的存在。Mediator 通过这种方式将多对多的通信简化为了一(Mediator)对多(Colleague)的通信。 


二、实例:


      各位好,大家都是来自五湖四海,都要生存,于是都找了个靠山——公司,给你发薪水的地方,那公司就要想尽办法盈利赚钱,盈利方法则不尽相同,但是作为公司都有相同三个环节:采购、销售和库存,这个怎么说呢?比如一个软件公司,要开发软件,需要开发环境吧, Windows 操作系统,数据库产品等,这你得买吧,那就是采购,开发完毕一个产品还要把产品推销出去,推销出去了大家才有钱赚,不推销出去大家都去喝西北风呀,既然有产品就必然有库存,软件产品也有库存,你总要拷贝吧,虽然是不需要占用库房空间,那也是要占用光盘或硬盘,这也是库存,再比如做咨询服务的公司,它要采购什么?采购知识,采购经验,这是这类企业的生存之本,销售的也是知识和经验,库存同样是知识和经验。尽然进销存是这么的重要,我们今天就来讲讲它的原理和设计,我相信很多人都已经开发过这种类型的软件,基本上都形成了固定套路,不管是单机版还是网络版,一般的做法都是通过数据库来完成相关产品的管理,相对来说还是比较简单的项目,三个模块之间的示意图如下: 


设计方式(c++)笔记之十八(Mediator模式)


      我们从这个示意图上可以看出,三个模块是相互依赖的,基本上是你中有我,我中有你,为什么呢?我们就以一个终端销售商(什么是终端销售商?就是以服务最终客户为目标的企业,比如 XX 超市,国美电器等等)为例子,比如采购部门要采购 IBM 型号的电脑了,它是根据什么来决定采购的呢?根据两个要素:
销售情况。销售部门要反馈销售情况,畅销就多采购,滞销就不采购;库存情况。即使是畅销产品,库存都有 1000 台了,每天才卖出去 10 台,还要采购吗?!销售模块是企业的盈利核心,也是对其他两个模块有影响的:库存情况。库房有货,才能销售,没货空手套白狼是不行的;督促采购。在特殊情况下,比如一个企业客户一下子要卖 100 台电脑,你库存里* 80 台,怎么办?

      催采购部门赶快采购呀!

      同样的,库存管理也对其他两个模块有影响,库房是有容积限制的,不可能无限大,所以就有了清仓处理,那就要求采购部门别采购了,同时销售部门赶快打折销售。
      从以上分析来看,这三个模块都是有自己的行为,并且与其他模块之间的行为产生关联关系,就类似我们在办公室中的同事,大家各干各的活,但是彼此之间还是有交叉的,于是乎大家之间就产生紧耦合,也就是一个团队。


我们先来实现这个进销存,先看类图:


设计方式(c++)笔记之十八(Mediator模式)


Purchase 负责采购管理,buyIBMComputer 是指定了采购 IBM 电脑,refuseBuyIBM 是不再采购 IBM 了 。

      你难道就没有发现这三个类间是彼此关联的吗?每个类都与其他两个类产生了关联关系,迪米特法则教育我们“每个类只和朋友类交流”,这个朋友类可不是越多越好,越多耦合性越大,改一个对象而要修改一片对象,这可不是面向对象设计所期望的,而且这还是就三个模块的情况,比较简单的一个小项目,如果有十个八个这样的模块是不是就要歇菜了,我们把进销存扩充一下,如下图的情况: 


设计方式(c++)笔记之十八(Mediator模式)



      是不是看到一个蜘蛛网的结构,这个别说是编写程序了,就是给人看估计能让一大批的人昏倒!每个对象都要和其他的几个对象交流,对象越多,每个对象要交流的成本也就越多了,就单独维护这些对象的交流基本上就能让一大批程序员望而却步,这明摆着不是人干的活嘛!从这方面来,我们已经发现设计的缺陷,作为一个架构师,发现缺陷就要想办法来修改,我们思考一下,怎么来修改。


      大家都是学计算机的,应该在上学的时候讲过一些网络的基本知识,还记得网络拓扑有几种类型吗?总线型,环型,星型,(什么?想不起来?!惩罚一下自己去),我们来想想星型拓扑是什么什么样子的,如下图: 



设计方式(c++)笔记之十八(Mediator模式)




      星型网络拓扑中每个计算机通过交换机和其他计算机进行数据交换,各个计算机之间并没有直接出现交互的情况,结构简单,而且稳定,只要中间那个交换机不瘫痪,整个网络就不会发生大的故障,公司和网吧一般都采用星型网络,那也说明星型拓扑是深得民心,那我们来想想是不是可以把这种星型结构引入到我们的设计中呢?说干就干,我们先画一个示意图:


设计方式(c++)笔记之十八(Mediator模式)




      加入了一个中介者作为三个模块的交流核心,每个模块之间不再相互交流,要交流就通过中介者进行,每个模块只负责自己的业务逻辑,不属于自己的则丢给中介者来处理,看类图:


设计方式(c++)笔记之十八(Mediator模式)


我的工程目录:


            设计方式(c++)笔记之十八(Mediator模式)


注释:

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;
}

结果如下:


设计方式(c++)笔记之十八(Mediator模式)


参考文献:《设计模式之禅》,《GoF_23种设计模式解析》