zoukankan      html  css  js  c++  java
  • 第12章 结构型模式—外观模式

    1. 外观(门面)模式(Facade Pattern)的定义

    (1)为子系统中的一组接口提供一个一致的界面,Façade模式定义了一个高层接口,这个接口使得这一子系统更加容易使用。

      ①这里说的界面是指从一个组件外部来看这个组件,能够看到什么,也就是外观。如从一个类外部看这个类,那么这个类的public方法或接口就是他的外观。

      ②这里所说的“接口”是指外部和内部交互的一个通道(方法),可以是类的方法,也可以是interface的方法。

     

    (2)外观模式的结构和说明

     

      ①Façade:定义子系统的多个模块对外的高层接口,通常需要调用内部多个模块,从而把客户的请求代理给适当的子系统对象

      ②模块:接受Façade对象的委派,真正实现功能,各个模块之间可能有交互。但请注意,Façade对象知道各个模块,但是各个模块不应该知道Façade对象。

    (3)思考外观模式

      ①外观模式的本质封装交互、简化调用。Façade封装了子系统外部和子系统内部多个模块的交互过程,从而简化了外部的调用,通过外观,子系统为外部提供一些高层的接口,以方便它们的使用。它很好的体现了“最少知识原则(DoL)”

      ②外观模式的目的:外观模式的目的不是给子系统添加新的功能接口,而是为了让外部减少与子系统内部多个模块的交互,松散耦合,从而让外部能够更简单地使用子系统

      ③Façade表面上看只是把客户端的代搬到了Façade里,但是有本质上的区别。因为Façade位于系统而不是客户端的一侧,它相当于屏蔽了外部客户端和系统内部模块的交互,同时Façade可以被多个客户端调用,实现复用

      ④外观是当作子系统对外的接口出现的,虽然可以在这里定义一些子系统没有的功能,但不建议这样做。外观应该是包装己有的功能,而不是添加新的功能。因为有时客户端可能需要绕开Façade,直接调用某个具体模块。而如果在Façade中添加新的功能,但可能最后调用的结果是不同的。

      ⑤外观可以提供一些缺省的功能实现。

    【编程实验】注册公司(通过外观模式提供简化的办理流程)

    //结构型模式:外观模式
    //场景:注册公司。
    
    #include <iostream>
    
    using namespace std;
    
    //质检局:Quality Supervision Burean
    class IQSBureau
    {
    public: 
        //到质检局办理组织机构代码证
        virtual void orgCodeCertificate() = 0;
    };
    
    class QSBureau : public IQSBureau
    {
    public:
        void orgCodeCertificate()
        {
            cout <<"QSBureau: orgCodeCertificate()" << endl;
        }    
    };
    
    //工商局:Industrial and Commercial Bureau
    class IICBureau
    {
    public:
        //检查名字是否冲突
        virtual void checkName() = 0;
    };
    
    class ICBureau : public IICBureau
    {
    public:
        void checkName() 
        {
             cout << "ICBureau: checkName()" << endl;   
        }
    };
    
    //税务局: Tax Bureau;
    class ITaxBureau
    {
    public:
        //办理税务登记证
        virtual void taxCertificate() = 0;  
    };
    
    class TaxBureau: public ITaxBureau
    {
    public:
        void taxCertificate() 
        {
            cout << "TaxBureau: taxCertificate()" << endl;
        }    
    };
    
    //银行:Bank;
    class IBank
    {
    public:
        //到银行开户
        virtual void openAccout() = 0;
    };
    
    class Bank : public IBank
    {
    public:
        void openAccout()
        {
            cout <<"Bank: openAcount()" << endl;
        }
    };
    
    //提供一个外观类(注册公司)
    class RegisterFacade
    {
    private:
        IICBureau* ic;
        IQSBureau* qs;
        IBank*     bank;
        ITaxBureau* tb;
    public:
        RegisterFacade()
        {
            ic = new ICBureau();
            qs = new QSBureau();
            bank = new Bank();
            tb = new TaxBureau();
        }
        
        void registerCompany()
        {
            ic->checkName(); //工商局
            qs->orgCodeCertificate(); //质检局
            tb->taxCertificate();     //税务局
            bank->openAccout();       //银行开户              
        }  
        
        ~RegisterFacade()
        {
            delete ic;
            delete qs;
            delete bank;
            delete tb;
        }    
    };
    
    int main()
    { 
        //客户端调用
        RegisterFacade rf;
        rf.registerCompany();
        
        return 0;
    }

    2. 外观模式的实现

    (1)Façade的实现

      对于一个子系统而言,外观类不需要很多,通常可以实现成一个单例。也可以直接把外观中的方法实现成静态方法,这样就可以不需要创建外观对象就可以直接调用,这种实现相当于把外观类当成一个辅助的工具类实现。

    (2)Façade可以实现为Interface

      通常Façade直接实现为为,但是也可以实现成真正的接口,这里还需要一个Façade的实现,一般可以用工厂方法来获取实现Façade接口的对象。实现为接口的好处是能够有选择地暴露接口,尽量减少模块对子系统对外提供的接口方法。

    3)Façade的方法

      一般是负责把客户端的请求转发给子系统内部的各个模块进行处理, Façade的方法实现的只是一个功能的组合调用和转发。但Façade不应参与子系统内的业务逻辑,这会导致子系统必须依赖外观才能被访问,这超出了Façade的本意,也违反了单一职责原则。

    3. 外观模式的优缺点

    (1)优点

      ①松散耦合:外观模式松散了客户端与子系统的耦合,让子系统内部的模块能更容易扩展和维护

      ②简单易用:客户端不再需要了解子系统内部实现,也不需要与众多的子系统内部模块进行交互,只需要跟外观交互就可以了。相当于外部类为客户端使用子系统提供了一站式服务

      ③更好地划分访问的层次。有些方法是对系统外的,有些是系统内部使用的。把需要暴露给外部的功能集中到外观中,这样既方便客户端使用,也很好地隐藏了内部的细节。

    (2)缺点:不符合开闭原则,有时可能需要修改外观角色的代码;过多使用Façade容易让人迷惑。

    4. 外观模式的使用场景

    (1)为一个复杂的模块或子系统提供一个外界访问的接口

    (2)子系统相对独立,外界对子系统访问只要黑箱操作即可。如利息计算很复杂,需要深厚的业务知识和扎实的技术水平。但对于客户端来讲,要求输入金额和存期,就可以返回最终的利息。这里可以用外观模式。

    (3)当需要构建一个层次结构的子系统时,使用Façade定义子系统中每层的入口点。如果子系统是相互依赖的,可以让它们仅通过Façade进行通讯,从而简化它们的依赖关系。

    【编程实验】编译过程的模拟

    //结构型模式:外观模式
    //场景:编译过程的简化。
    //编译器内部所做的事情:词法分析、语法分析、代码优化、代码生成等
    //对于客户端来讲,只要给文件路径,只能产生最终的结果。编译器内部所做的
    //事情对客户端来说是透明的。
    #include <iostream>
    
    using namespace std;
    
    //扫描器
    class Scanner
    {
    public: 
        void scan(const char* lpszInput) 
        {
            cout <<"Scanning: " << lpszInput << endl;
        }    
    };
    
    //分析器
    class Parser
    {
    public:
        void parse(const char* lpszInput)
        {
            cout <<"Analysing: " << lpszInput << endl;
        }
    };
    
    //代码生成器
    class CodeGenerator
    {
    public:
        void codeGen(const char* lpszOutput)
        {
            cout <<"Code generate, output to: " << lpszOutput<< endl;
        }
    };
    
    //提供一个外观类(编译器)
    class Compiler
    {
    private:
        Scanner s;
        Parser  p;
        CodeGenerator c;
    public:
        void compile(const char* lpszInput, const char* lpszOutput)
        {
            s.scan(lpszInput);
            p.parse(lpszInput);
            c.codeGen(lpszOutput);
        }    
    };
    
    //使用编译系统:这个系统包括扫描器、分析器、生成器。并且提供了一个外观接口
    //Compiler类
    int main()
    { 
        //客户端调用
        Compiler c;
        c.compile("123.cpp", "123.exe");
        
        return 0;
    }

    5. 相关模式

    (1)外观模式与中介者模式

      ①这两者很相似,但有本质的区别

      ②中介者用来封装多个对象之间的交互,多用在系统内部的多个模块之间;而外观的封装是单向的交互,是从客户端访问系统的调用,没有从系统中来访问客户端的调用。

      ③在中介者模式的实现里面,需要实现具体的交互功能;而外观模式的实现里面,一般是组合调用或转调内部实现的功能,通常外观模式本身并不实现这些功能。

      ④中介者模式的目的主要是松散多个模块之间的耦合,把这些耦合关系全部放到中介者中去实现;而外观模式的目的是简化客户端的调用。

  • 相关阅读:
    FCKeditor 2.6.4在ASP.NET中的安装、配置方法【转】 Fred
    框架页中针对IE6自适应宽度,不出现横向滚动条 Fred
    安装中文VS2008 SP1 和.NETFRAMEWORK 3.5SP1后智能提示是英文的解决办法 Fred
    .Net转义字符[转] Fred
    ReportViewer无法直接打印 Fred
    ASP.NET MVC 官方教程 Fred
    修改SQL Server 2005 sa用户密码的方法 Fred
    数据类型/对象类型介绍(1)NSString
    关于Chrome沙箱技术(沙盒技术)
    UITableView cell自定义视图中插入Table实现复杂界面
  • 原文地址:https://www.cnblogs.com/5iedu/p/5538954.html
Copyright © 2011-2022 走看看