设计模式之外观模式

2018-09-20 01:33:12

外观模式(Facade Pattern)

  还是用大话设计模式中的例子:股票和基金来说明外观模式。股票买入者直接操作股票,他需要了解几千只股票的各种信息还需要预测它的涨跌,这样买入者和股票直接有着直接的联系,在软件开发种,这就是高耦合(模块和模块之间的联系过多)。买入基金,则由专业的基金经理人操作用户的资源,买入者只需要和基金经理人打交道,具体股票的细节,则由基金经理人来处理。

  外观模式(Facade Pattern)又称门面模式:为子系统中的一组接口提供一个一致的界面,此模式定义了一个高层接口,这个接口使得这一子系统更加容易使用。

UML类图

其中:SubSystemOne、SubSystemTwo、SubSystemThree、SubSystemFour 构成了一个子系统。

Facade:外观类,知道哪些子系统,它们有哪些功能,一般Client把像子系统的请求委托给Facade,然后Facade再把这个请求转给适合的子系统对象。(System和Facade其实是聚合关系,它们之间没有太多的耦合性)

SubSystem:子系统,子系统可以同时有多个,一个系统可以是类的集合或者是一个单独的类。每个子系统可以单独被Client调用也可以被Facade调用,对于Client来说它不知道有Facade的存在,Facade对子系统而言就是一个Client。

外观模式的优缺点

优点:

  1.Client只与Facade打交道,降低了Client代码的复杂度。

  2.降低了Client和System的耦合度,子系统有调整时不会影响到Client或者影响较小,能够通过调整Facade来适应子系统的改变。

  3.降低了大型软件中的编译依赖性,并简化了系统在不同平台之间而定移植过程,因为设计良好的子系统,一般而言是相互独立的,一个系统的改变不会影响到其它子系统,而子系统的内部变化(指实现细节)也不会影响到外观,所以只需要编译有变化的子系统即可(对GCC编译器)。

  4.模式仅提供了一个访问子系统的统一入口,但是并不阻止用户直接使用子系统类。

 

缺点:

  1.不能很好地限制Client使用子系统,如果要给Client添加使用限制,将可能是整个模式丧失它的灵活性,也会增加其复杂度(试想一下为每个子系统添加定制化的限制,在实现是将会有多复杂)

  2.在不引入抽象外观类(Facade)的情况下,增加子系统,要对应的调整Facade和Client(考虑下简单工厂模式),这会违背开放-封闭原则。

使用场景

  • 当要为一个复杂子系统提供一个简单接口时。该接口可以满足大多数用户的需求,而且用户也可以越过外观类直接访问子系统。
  • Client 与多个子系统之间存在很大的依赖性。引入外观类将子系统与 Client 以及其他子系统解耦,可以提高子系统的独立性和可移植性。
  • 在层次化结构中,可以使用外观模式定义系统中每一层的入口。层与层之间不直接产生联系,而通过外观类建立联系,降低层之间的耦合度。

代码示例

  问题模型:假设我们在开发一个GUI程序,通过界面我们能够产生一组通用数据,但是这组通用数据需要被不同的子系统按需选择,并进行对应的处理。比如我们能在bash终端输入不同的命令调用不同的处理程序。我们假设这是一个外观模式(但真实的应用情况不是这样,因为,linux下的各种命令实际上是由个人开发者自行开发的程序,在使用时,bash终端输入程序名 参数即可使用命令提供的服务)。那么现在main函数就是客户代码,S1表示调用子系统S1执行某种操作,S2表示调用S2执行某种操作等等。网上有个电商的例子,我觉得比较好,它没有我这个这么理想化,子系统之间的数据没有耦合。

1.3个子系统

#ifndef SUBSYSTEMA_H_
#define SUBSYSTEMA_H_

#include <iostream>

class SubSystemA
{
public:
    void methodA()
    {
    std::cout << "I am SystemA!" << std::endl;
    }
    SubSystemA() = default;
    ~SubSystemA() = default;
};
#endif
SubSystemA
#ifndef SUBSYSTEMB_H_
#define SUBSYSTEMB_H_
#include <iostream>
#include <ctime>
class SubSystemB
{
public:
    void methodB()
    {
    auto systTime = time(nullptr);
        tm *struSysTime = localtime(&systTime);
    char szTime[16] = {0};
        sprintf(szTime,"%04d-%02d-%02d",struSysTime->tm_year+1990,struSysTime->tm_mon+1,struSysTime->tm_mday);
    std::cout << "Today is:" << szTime << std::endl;
    }
    SubSystemB() = default;
    ~SubSystemB() = default;
};
#endif
SubSystemB
#ifndef SUBSYSTEMC_H_
#define SUBSYSTEMC_H_

#include <iostream>
#include <ctime>

class SubSystemC
{
public:
    void methodC()
    {
    auto systTime = time(nullptr);
    tm *struSysTime = localtime(&systTime);
        char szTime[16] = {0};
        sprintf(szTime,"%02d:%02d:%02d",struSysTime->tm_hour,struSysTime->tm_min,struSysTime->tm_sec);
    std::cout << "Now Time is:"<< szTime << std::endl;
    }
    SubSystemC() = default;
    ~SubSystemC() = default;
};
#endif
SubsystemC

2.Facade外观类,也是这个模式的核心

#ifndef FACADE_H_
#define FACADE_H_
#include "SubSystemA.h"
#include "SubSystemB.h"
#include "SubSystemC.h"
#include <string>
class Facade
{
public:
    void noteSubSystem(const std::string strParam);
    Facade() = default;
    ~Facade() = default;
private:
    SubSystemA m_objSubSystemA;
    SubSystemB m_objSubSystemB;
    SubSystemC m_objSubSystemC;
};
#endif 

#include "Facade.h"

void Facade::noteSubSystem(const std::string strSystemName)
{
    if(strSystemName == "SubSystemA")
    m_objSubSystemA.methodA();
    else if(strSystemName == "SubSystemB")
    m_objSubSystemB.methodB();
    else if(strSystemName == "SubSystemC")
    m_objSubSystemC.methodC();
    else
    std::cout << "Param Error" << std::endl;
}    
Facade

3.客户端代码

#include "Facade.h"

using namespace std;

int main(int argc,char*argv[])
{
    if(argc != 2)
    {
    std::cout << "The count of param is Error!" <<std::endl;
    return (0);
    }
    std::string strParam = argv[1];
    Facade objFacade;
    objFacade.noteSubSystem(strParam);
    return (1);
}
Client

 

  外观模式的使用:

  1.在设计阶段就要有意识的把不同的层分离(三层架构:数据访问层、业务逻辑层、表示层,在层与层之间建立外观Facade)

  2.开发阶段,子系统因为不断的重构变的越来越复杂。增加外观模式。可以提供一个简单的接口,减少它们之间的依赖

  3.为新系统开发一个外观Facade类,来提供设计粗糙或高度负责的遗留代码的比较清晰简单的接口,让新系统与Facade对象交互,Facade与遗留代码交互所有的复杂工作。

 

 

 

 

 

 

 

d

posted on 2018-09-20 10:52  古I月  阅读(171)  评论(0编辑  收藏  举报

导航