【设计模式】 模式PK:门面模式VS中介者模式

1、概述

门面模式为复杂的子系统提供一个统一的访问界面,它定义的是一个高层接口,该接口使得子系统更加容易使用,避免外部模块深入到子系统内部而产生与子系统内部细节耦合的问题。中介者模式使用一个中介对象来封装一系列同事对象的交互行为,它使各对象之间不再显式地引用,从而使其耦合松散,建立一个可扩展的应用架构。

2、中介者模式实现工资计算

2.1 类图

大家工作会得到工资,那么工资与哪些因素有关呢?这里假设工资与职位、税收有关,职位提升工资就会增加,同时税收也增加,职位下降了工资也同步降低,当然税收也降低。而如果税收比率增加了呢?工资自然就减少了!这三者之间两两都有关系,很适合中介者模式的场景。

类图中的方法比较简单,我们主要分析的是三者之间的关系,通过类图可以发现三者之间已经没有耦合,原本在需求分析时我们发现三者有直接的交互,采用中介者模式后,三个对象之间已经相互独立了,全部委托中介者完成。我们在类图中还定义了一个抽象同事类,它是一个标志性接口,其子类都是同事类,都可以被中介者接收。

2.2 代码

2.2.1 抽象同事类

// CAbsColleague.h
class CAbsColleague
{
public:
    CAbsColleague(CAbsMediator *opMediator);
    ~CAbsColleague();

protected:
    //每个同事类都对中介者非常了解
    CAbsMediator *mopMediator;
};

// CAbsColleague.cpp
CAbsColleague::CAbsColleague(CAbsMediator *opMediator) :mopMediator(opMediator){}

CAbsColleague::~CAbsColleague(){}

抽象同事类中定义了每个同事类对中介者都非常了解,如此才能把请求委托给中介者完成。三个同事类都具有相同的设计,即定义一个业务接口以及每个对象必须实现的职责,同时既然是同事类就都继承CAbsColleague。抽象同事类只是一个标志性父类,并没有限制子类的业务逻辑,因此每一个同事类并没有违背单一职责原则。

2.2.2 职位

// CIPosition.h
class CIPosition
{
public:
    CIPosition();
    ~CIPosition();

    virtual void mvPromote() = 0;
    virtual void mvDemote() = 0;
};

// CIPosition.cpp
CIPosition::CIPosition(){};

CIPosition::~CIPosition(){};

职位会有升有降。

// CPosition.h
class CPosition : public CAbsColleague, public CIPosition
{
public:
    CPosition(CAbsMediator *opMediator);
    ~CPosition();

    void mvPromote();

    void mvDemote();
};

// CPosition.cpp
CPosition::CPosition(CAbsMediator *opMediator) : CAbsColleague(opMediator)
{
    mopMediator->mvSetPosition(this);
}

CPosition::~CPosition(){}

void CPosition::mvPromote()
{
    mopMediator->mvUp(this);
}

void CPosition::mvDemote()
{
    mopMediator->mvDown(this);
}

每一个职位的升降动作都委托给中介者执行,具体一个职位升降影响到谁这里没有定义,完全由中介者完成,简单而且扩展性非常好。

2.2.3 工资

// CISalary.h
class CISalary
{
public:
    CISalary();
    ~CISalary();

    //加薪
    virtual void mvIncreaseSalary() = 0;

    //降薪
    virtual void mvDecreaseSalary() = 0;
};
// CISalary.cpp
CISalary::CISalary(){}

CISalary::~CISalary(){}

工资也会有升有降。

// CSalary.h
class CSalary :public CAbsColleague, public CISalary
{
public:
    CSalary(CAbsMediator *opMediator);
    ~CSalary();

    void mvIncreaseSalary();

    void mvDecreaseSalary();
};

// CSalary.cpp
CSalary::CSalary(CAbsMediator *opMediator) : CAbsColleague(opMediator)
{
    mopMediator->mvSetSalary(this);
}

CSalary::~CSalary(){}

void CSalary::mvIncreaseSalary()
{
    mopMediator->mvUp(this);
}

void CSalary::mvDecreaseSalary()
{
    mopMediator->mvDown(this);
}

2.2.4 税收

// CITax.h
class CITax
{
public:
    CITax();
    ~CITax();

    //  税收上升
    virtual void mvRaise() = 0;

    // 税收下降
    virtual void mvDrop() = 0;
};

// CITax.cpp
CITax::CITax(){}

CITax::~CITax(){}

税收同样有升有降。

//CTax.h
class CTax : public CAbsColleague, public CITax
{
public:
    CTax(CAbsMediator *opMediator);
    ~CTax();

    void mvRaise();

    void mvDrop();
};

// CTax.cpp
CTax::CTax(CAbsMediator *opMediator) : CAbsColleague(opMediator)
{
    mopMediator->mvSetTax(this);
}

CTax::~CTax(){}

void CTax::mvRaise()
{
    mopMediator->mvUp(this);
}

void CTax::mvDrop()
{
    mopMediator->mvDown(this);
}

2.2.5 中介类

以上同事类的业务都委托给了中介者,其本类已经没有任何的逻辑了,非常简单,现在的问题是中介者类非常复杂,因为它要处理三者之间的关系。

// CAbsMediator.h
class CAbsMediator
{
public:
    CAbsMediator();

    ~CAbsMediator();

    void mvSetSalary(CISalary *opSalary);

    void mvSetPosition(CIPosition *opPosition);

    void mvSetTax(CITax *opTax);

    // 工资增加了
    virtual void mvUp(CISalary *opSalary) = 0;
    //职位提升了
    virtual void mvUp(CIPosition *opPosition) = 0;
    //税收增加了
    virtual void mvUp(CITax *opTax) = 0;
    //工资降低了
    virtual void mvDown(CISalary *opSalary) = 0;
    //职位降低了
    virtual void mvDown(CIPosition *opPosition) = 0;
    //税收降低了
    virtual void mvDown(CITax *opTax) = 0;

protected:
    //工资
    CISalary *mopSalary;
    //职位
    CIPosition *mopPosition;
    //税收
    CITax *mopTax;
};

// CAbsMediator.cpp
CAbsMediator::CAbsMediator(){}

CAbsMediator::~CAbsMediator(){}

void CAbsMediator::mvSetSalary(CISalary *opSalary)
{
    mopSalary = opSalary;
}

void CAbsMediator::mvSetPosition(CIPosition *opPosition)
{
    mopPosition = opPosition;
}

void CAbsMediator::mvSetTax(CITax *opTax)
{
    mopTax = opTax;
}

在抽象中介者中我们定义了6个方法,分别处理职位升降、工资升降以及税收升降的业务逻辑,采用多态机制来实现。我们来看具体的实现类。

// CMediator.h
class CMediator : public CAbsMediator
{
public:
    CMediator();
    ~CMediator();

    // 工资增加了
    void mvUp(CISalary *opSalary);

    //职位提升了
    void mvUp(CIPosition *opPosition);

    //税收增加了
    void mvUp(CITax *opTax);

    //工资降低了
    void mvDown(CISalary *opSalary);

    //职位降低了
    void mvDown(CIPosition *opPosition);

    //税收降低了
    void mvDown(CITax *opTax);
};

// CMediator.cpp
CMediator::CMediator(){}

CMediator::~CMediator(){}

// 工资增加了
void CMediator::mvUp(CISalary *opSalary)
{
    cout << "增加税收" << endl;
    cout << "增加工资" << endl;
}

//职位提升了
void CMediator::mvUp(CIPosition *opPosition)
{
    cout << "增加税收." << endl;
    cout << "增加工资." << endl;
    cout << "提升职位." << endl;
}

//税收增加了
void CMediator::mvUp(CITax *opTax)
{
    cout << "增加税收." << endl;
    cout << "增加工资." << endl;
}

//工资降低了
void CMediator::mvDown(CISalary *opSalary)
{
    cout << "减少税收. " << endl;
    cout << "降低工资." << endl;
}

//职位降低了
void CMediator::mvDown(CIPosition *opPosition)
{
    cout << "减少税收. " << endl;
    cout << "降低工资." << endl;
    cout << "降低职位." << endl;
}

//税收降低了
void CMediator::mvDown(CITax *opTax)
{
    cout << "减少税收. " << endl;
    cout << "降低工资." << endl;
}

该类的方法较多,但是还是非常简单的,它的方法分为两大类型:一类是每个业务的独立流程,比如增加工资,仅仅实现单独增加工资的职能,而不关心职位、税收是如何变化的,该类型的方法是private私有类型,只能提供本类内访问,这里为了方便使用打印来替代调用的处理方法;另一类是实现抽象中介者定义的方法,完成具体的每一个逻辑,比如职位上升,同时也引起了工资增加、税收增加。

2.2.6 场景调用

int main()
{
    //定义中介者
    CAbsMediator *op_mediator = new CMediator;
    //定义各个同事类
    CIPosition *op_position = new CPosition(op_mediator);
    CISalary *op_salary = new CSalary(op_mediator);
    CITax *op_tax = new CTax(op_mediator);

    //职位提升了
    cout << "===职位提升===" << endl;
    op_position->mvPromote();

    return 0;
}

2.2.7 执行结果

2.3 小结

我们回过头来分析一下设计,在接收到需求后我们发现职位、工资、税收之间有着紧密的耦合关系,如果不采用中介者模式,则每个对象都要与其他两个对象进行通信,这势必会增加系统的复杂性,同时也使系统处于僵化状态,很难实现拥抱变化的理想。通过增加一个中介者,每个同事类的职位、工资、税收都只与中介者通信,中介者封装了各个同事类之间的逻辑关系,方便系统的扩展和维护。

3、门面模式实现工资计算

3.1 类图

工资计算是一件非常复杂的事情,简单来说,它是对基本工资、月奖金、岗位津贴、绩效、考勤、税收、福利等因素综合运算后的一个数字。即使设计一个HR(人力资源)系统,员工工资计算也是非常复杂的模块,但是对于外界,比如高管层,最希望看到的结果是张三拿了多少钱,李四拿了多少钱,而不是看中间的计算过程,怎么计算那是人事部门的事情。换句话说,对外界的访问者来说,它只要传递进去一个人员名称和月份即可获得工资数,而不用关心其中的计算有多么复杂,这就用得上门面模式了。

门面模式对子系统起封装作用,它可以提供一个统一的对外服务接口。

该类图主要实现了工资计算,通过HRFacade门面可以查询用户的工资以及出勤天数等,而不用关心这个工资或者出勤天数是怎么计算出来的,从而屏蔽了外系统对工资计算模块的内部细节依赖。

3.2 代码

我们先看子系统内部的各个实现。

3.2.1 考勤情况

非常简单, 只用一个方法获得一个员工的出勤天数。

class CAttendance
{
public:
    CAttendance(){}
    ~CAttendance(){}

    //得到出勤天数
    int miGetWorkDays()
    {
        return rand() % 30;
    }
};

3.2.2 奖金计算

我们在这里实现了一个示意方法,实际的奖金计算是非常复杂的,与考勤、绩效、基本工资、岗位都有关系,单单一个奖金计算就可以设计出一个门面。

class CBonus
{
public:
    CBonus() { mopAttendance = new CAttendance; }

    //奖金
    int miGetBonus()
    {
        //获得出勤情况
        int i_work = mopAttendance->miGetWorkDays();
        //奖金计算模型
        int i_bonus = i_work * 1800 / 30;

        return i_bonus;
    }
private:
    //考勤情况
    CAttendance *mopAttendance;
};

3.2.3 基本工资

我们再来看基本工资,这个基本上是按照职位而定的,比较固定。我们定义了员工的基本工资都为2000元, 没有任何浮动的余地。

class CBasicSalary
{
public:
    CBasicSalary(){}
    ~CBasicSalary(){}

    //获得一个人的基本工资
    int miGetBasicSalary() { return 2000; }
};

3.2.4 绩效

绩效按照一个非常简单的算法,即基本工资乘以一个随机的百分比。

class CPerformance
{
public:
    CPerformance(){ mopBasicSalary = new CBasicSalary; }
    ~CPerformance(){}

    //绩效奖励
    int miGetPerformance()
    {
        //随机绩效
        int i_perf = rand() % 100;
        return mopBasicSalary->miGetBasicSalary()*i_perf / 100;
    }

private:
    CBasicSalary *mopBasicSalary;
};

3.2.5 税收

class CTax
{
public:
    CTax(){}
    ~CTax(){}

    //收取多少税金
    int miGetTax()
    {
        //交纳一个随机数量的税金
        return rand() % 300;
    }
};

3.2.6 薪酬

一个计算员工薪酬的所有子元素都已经具备了,剩下的就是编写组合逻辑类,总工资的计算。

这里只是对前面的元素值做了一个加减法计算,这是对实际HR系统的简化处理,如果把这个类暴露给外系统,那么被修改的风险是非常大的,因为它的方法miGetTotalSalary是一个具体的业务逻辑。我们采用门面模式的目的是要求门面是无逻辑的,与业务无关,只是一个子系统的访问入口。门面模式只是一个技术层次上的实现, 全部业务还是在子系统内实现。

class CSalaryProvider
{
public:
    CSalaryProvider()
    {
        mopBasicSalary = new CBasicSalary;
        mopBonus = new CBonus;
        mopPerf = new CPerformance;
        mopTax = new CTax;
    }

    ~CSalaryProvider(){}

    int miGetTotalSalary()
    {
        return mopBasicSalary->miGetBasicSalary() + mopBonus->miGetBonus() + mopPerf->miGetPerformance() - mopTax->miGetTax();
    }
private:
    //基本工资
    CBasicSalary *mopBasicSalary;
    //奖金
    CBonus *mopBonus;
    //绩效
    CPerformance *mopPerf;
    //税收
    CTax *mopTax;
};

3.2.7 HR门面

所有的行为都是委托行为,由具体的子系统实现,门面只是提供了一个统一访问的基础而已,不做任何的校验、判断、异常等处理。

class CHRFacade
{
public:
    CHRFacade()
    {
        mopSalary = new CSalaryProvider;
        mopAttendance = new CAttendance;
    }

    ~CHRFacade(){}

    //查询一个人的总收入
    int miGetSalary(const string &sName, int iWork)
    {
        return mopSalary->miGetTotalSalary();
    }

    //查询一个员工一个月工作了多少天
    int miGetWorkDays(const string &sName)
    {
        return mopAttendance->miGetWorkDays();
    }

private:
    //总工资情况
    CSalaryProvider *mopSalary;
    //考勤情况
    CAttendance *mopAttendance;
};

3.2.8 场景调用

int main()
{
        //定义门面
        CHRFacade *op_facede = new CHRFacade;

        //查询工资
        cout << "===外系统查询总收入===" << endl;
        int i_salary = op_facede->miGetSalary("张三", rand()%30);
        cout << "张三 11月 总收入为: " << i_salary << endl;

        //再查询出勤天数
        cout << "===外系统查询出勤天数===" << endl;
        int i_work_day = op_facede->miGetWorkDays("李四");
        cout << "李四 本月出勤:  " << i_work_day << endl;

    return 0;
}

3.2.9 运行结果

3.3 小结

在该例中,我们使用了门面模式对薪水计算子系统进行封装,避免子系统内部复杂逻辑外泄,确保子系统的业务逻辑的单纯性,即使业务流程需要变更,影响的也是子系统内部功能,比如奖金需要与基本工资挂钩,这样的修改对外系统来说是透明的,只需要子系统内部变更即可。

4、总结

门面模式和中介者模式之间的区别还是比较明显的,门面模式是以封装和隔离为主要任务,而中介者模式则是以调和同事类之间的关系为主,因为要调和,所以具有了部分的业务逻辑控制。两者的主要区别如下:

● 功能区别

门面模式只是增加了一个门面, 它对子系统来说没有增加任何的功能, 子系统若脱离门面模式是完全可以独立运行的。而中介者模式则增加了业务功能,它把各个同事类中的原有耦合关系移植到了中介者,同事类不可能脱离中介者而独立存在,除非是想增加系统的复杂性和降低扩展性。

● 知晓状态不同

对门面模式来说,子系统不知道有门面存在,而对中介者来说,每个同事类都知道中介者存在,因为要依靠中介者调和同事之间的关系,它们对中介者非常了解。

● 封装程度不同

门面模式是一种简单的封装,所有的请求处理都委托给子系统完成,而中介者模式则需要有一个中心,由中心协调同事类完成,并且中心本身也完成部分业务,它属于更进一步的业务功能封装。

时间: 2024-12-17 09:32:18

【设计模式】 模式PK:门面模式VS中介者模式的相关文章

《大话设计模式》学习笔记21:中介者模式

同事间接收消息示例: 1.Mediator: public abstract class Mediator { public abstract void Send(string message, Colleague colleague); } 2.Colleague: public abstract class Colleague { protected Mediator mediator; public Colleague(Mediator mediator) { this.mediator

Java设计模式菜鸟系列(二十二)中介者模式建模与实现

转载请注明出处:http://blog.csdn.net/lhy_ycu/article/details/40027109 中介者模式(Mediator):主要用来降低类与类之间的耦合的,因为如果类与类之间有依赖关系的话,不利于功能的拓展和维护,因为只要修改一个对象,其它关联的对象都得进行修改. 一.uml建模: 二.代码实现 /** * 中介者模式(Mediator):主要用来降低类与类之间的耦合的,因为如果类与类之间有依赖关系的话, * * 不利于功能的拓展和维护,因为只要修改一个对象,其它

大话设计模式C++实现-第25章-中介者模式

一.UML 二.概念 中介者模式(Mediator):用一个中介对象来封装一系列的对象交互.中介者使各对象不需要显示地相互引用,从而使其耦合松散,而且可以独立地改变它们之间的交互. 三.说明 角色: (1)Colleague:抽象同事类. (2)ConcreteClleague:具体同事类,每个具体同事只知道自己的行为,而不了解其他同事类的情况,但它们却都认识中介者对象. (3)Mediator:抽象中介者,定义了同事对象到中介者对象的接口. (4)ConcreteMediator:具体中介者对

设计模式C++实现二十一:中介者模式

中介者模式(Mediator):用一个中介对象来封装一系列的对象交互.中介者是各对象不需要显式地相互引用,从而使其耦合松散,而且可以独立地改变他们之间的交互. 中介者模式很容易在系统中应用,也很容易在系统中误用.当系统出现多对多交互复杂的对象群是,不要急于使用中介者模式,而要先反思你的系统在设计上是不是合理. 优点:Mediator的出现减少了各个colleague的耦合,使得可以独立地改变和复用各个colleague类和Mediator:由于把对象如何协作进行了抽象,将中介作为一个独立的概念并

【设计模式】 模式PK:观察者模式VS责任链模式

1.概述 为什么要把观察者模式和责任链模式放在一起对比呢?看起来这两个模式没有太多的相似性,真没有吗?回答是有.我们在观察者模式中也提到了触发链(也叫做观察者链)的问题,一个具体的角色既可以是观察者,也可以是被观察者,这样就形成了一个观察者链.这与责任链模式非常类似,它们都实现了事务的链条化处理,比如说在上课的时候你睡着了,打鼾声音太大,盖过了老师讲课声音,老师火了,捅到了校长这里,校长也处理不了,然后告状给你父母,于是你的魔鬼日子来临了,这是责任链模式,老师.校长.父母都是链中的一个具体角色,

设计模式之中介者模式20170731

行为型设计模式之中介者模式: 一.含义 用一个中介对象封装一系列的对象交互,中介者使各对象不需要显示地相互作用,从而使其耦合松散,而且可以独立地改变它们之间的交互. 同事角色与其他同时角色通信的时候,一定要通过中介者角色(中介者封装了各个同事类之间的逻辑关系) 二.代码说明 1.主要有两个角色 1)中介者角色 通过协调各同事角色实现协作行为,因此它必须依赖于各个同事角色. 2)同事角色 每一个同事角色都知道中介者角色,而且与其他的同事角色通信的时候,一定要通过中介者角色协作. 每个同事类的行为分

设计模式(十六)中介者模式(Mediator)-行为型

中介者模式Mediator 中介者模式又称作调停模式. 所谓中介,在我们生活中很是常见,我们买房子可以有中介公司,找兼职也可以有中介公司.以买房子为例.中介者把所有的买房人.卖房人的需求和特点都结合到一起,把适合的房子提供给合适的人. 首先我们要理解中介者模式的定义:用一个中介者对象来封装一系列对象的交互.中介者使得各对象不需要显式地相互引用,从而解耦合,独立改变他们之间的交互. 实现原理图 中介者模式的实现原理图 比较 门面模式PK中介者模式: 1.门面模式是结构型模式,中介者模式是行为型模式

[设计模式]中介者模式

1. 定义 用一个中介者对象来封装了一个系列对象的交互,中介者使得各个对象可以不需要显式的引用,而且可以独立改变对象之间的交互. 中介者模式思路很简单,中介者模式中通过引入一个中介者对象,让其他对象与中介者对象进行交互,而中介者对象知道如何和所有对象交互,这样对象之间的交互关系就没有了,从而实现对象之间解耦. 每个同事对象发生了变化,不需要知道这样会引起其他对象什么变化,只需要通知中介者,由中介者去与其他对象交互.这样的松耦合带来的好处是,同事对象之间的交互关系减少,而且有利于功能的修改和扩展.

设计模式之中介者模式(Mediator)摘录

23种GOF设计模式一般分为三大类:创建型模式.结构型模式.行为模式. 创建型模式抽象了实例化过程,它们帮助一个系统独立于如何创建.组合和表示它的那些对象.一个类创建型模式使用继承改变被实例化的类,而一个对象创建型模式将实例化委托给另一个对象.创建型模式有两个不断出现的主旋律.第一,它们都将关于该系统使用哪些具体的类的信息封装起来.第二,它们隐藏了这些类的实例是如何被创建和放在一起的.整个系统关于这些对象所知道的是由抽象类所定义的接口.因此,创建型模式在什么被创建,谁创建它,它是怎样被创建的,以

PHP设计模式——中介者模式

声明:本系列博客参考资料<大话设计模式>,作者程杰. 中介者模式用一个中介者对象来封装一系列的对象交互.中介者使得各对象不需要显式地相互引用,从而使其松散耦合,而且可以独立地改变它们之间的交互. UML类图: 角色: 中介者接口(UnitedNations):在里面定义了各个同事之间相互交互所需要的方法. 具体的中介者实现对象(UnitedCommit):它需要了解并为维护每个同事对象,并负责具体的协调各个同事对象的交互关系. 同事类的定义(Country):通常实现成为抽象类,主要负责约束同