zoukankan      html  css  js  c++  java
  • 设计模式之外观模式

    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

  • 相关阅读:
    写一个函数的程序,判断是否是浮点数
    写一个函数,输入一个数,随机生成N条邮箱
    day4-python基础知识 <元组&&集合>
    day4-python基础知识<文件操作>
    程序--用户登录--<while循环>
    程序--<猜数字小游戏>--for
    使用ajax后提交事件后禁用按钮,事件执行完毕后,重新启用按钮
    ajax在弹出对话框中实现一个UpdateProgress进度条控件源代码
    运算符的结合性
    匿名方法
  • 原文地址:https://www.cnblogs.com/ToBeExpert/p/9678588.html
Copyright © 2011-2022 走看看