设计模式学习笔记(十三):外观模式

1 概述

1.1 引言

根据单一权责原则,软件中将一个系统划分为若干个子系统有利于下降整个系统的复杂性,使客户类与子系统之间的通讯和相互依赖关系达到最小,方法之一就是引入一个外观角色,为子系统的访问提供一个简单而单一的入口。外观模式经过引入一个新的外观角色来下降原有系统的复杂度,同时下降客户类与子系统类的耦合度。java

(这里的子系统是广义的概念,能够是一个类,一个功能模块,系统的一个组成部分或者一个完整的系统)编程

若是没有外观角色,每一个客户端可能须要和多个子系统之间进行复杂的交互,系统的耦合度很大,简化示意图以下:设计模式

设计模式学习笔记(十三):外观模式

而引入外观角色后,客户端只需直接与外观角色交互,客户端与子系统之间的原有复杂度由外观角色实现,从而下降系统耦合度,简化示意图以下:微信

设计模式学习笔记(十三):外观模式

外观模式要求一个子系统的外部与其内部的通讯经过一个统一的外观角色进行,外观角色将客户端与子系统的内部复杂性分隔开,使得客户端只须要与外观角色打交道,而不须要与子系统内部的不少对象打交道。ide

1.2 定义

外观模式:外部与一个子系统的通讯经过一个统一的外观角色进行,为子系统中的一组接口提供一个一致的入口。学习

外观模式定义了一个高层接口,这个接口使得这一子系统更加容易使用。测试

外观模式又叫门面模式,是一种对象结构型模式。加密

1.3 结构图

设计模式学习笔记(十三):外观模式

1.4 角色

  • Facade(外观角色):在客户端能够调用这个角色的方法,在外观角色中能够知道相关的一个或多个子系统的功能和责任,正常状况下未来自客户端的请求委派到对应的子系统中去,传递给相应的子系统对象处理
  • SubSystem(子系统角色):每个子系统是一个单独的类,也能够是一个类的集合,实现子系统的功能。每个子系统均可以被客户端直接调用,或者被外观角色调用,它处理由外观类传过来的请求,子系统并不知道外观类的存在,对于子系统而已,外观角色仅仅是另外一个客户端

2 典型实现

2.1 步骤

  • 定义子系统:首先定义子系统,实现一个单一的功能,处理由客户端传来的请求
  • 定义外观角色:外观角色能够知道一个或多个子系统的功能和责任,未来自客户端的请求委派到对应的子系统去,外观角色对于子系统而言是另外一个客户端

2.2 外观角色

一般实现以下:设计

class Facade
{
    private SubSystemA subSystemA = new SubSystemA();
    private SubSystemB subSystemB = new SubSystemB();
    private SubSystemC subSystemC = new SubSystemC();

    public void method()
    {
        subSystemA.method();
        subSystemB.method();
        subSystemC.method();
    }
}

class SubSystemA
{
    public void method()
    {
        System.out.println("子系统A");
    }
}

class SubSystemB
{
    public void method()
    {
        System.out.println("子系统B");
    }
}

class SubSystemC
{
    public void method()
    {
        System.out.println("子系统C");
    }
}

2.3 客户端

使用外观模式的缘由就是简化客户端的调用,在这里只需定义外观对象并调用业务方法便可:code

Facade facade = new Facade();
facade.method();

3 实例

设计一个文件加密系统,加密流程包括三部分:读取文件,加密文件,保存文件。这三个操做相对独立,而且封装在三个不一样的类中,使用外观模式设计该系统。

设计以下:

  • 子系统类:FileReader+Encrypt+FileWriter
  • 外观角色类:Facade
  • FileReader:文件读取类
  • Encrypt:文件加密类
  • FileWriter:文件保存类

代码以下:

public class Test
{
    public static void main(String[] args) {
        Facade facade = new Facade();
        facade.fileEncrypt("111");
    }
}

class FileReader
{
    public void read(String name)
    {
        System.out.println("读取文件"+name);
    }
}

class Encrypt
{
    public void encrypt(String name)
    {
        System.out.println("加密文件"+name);
    }
}

class FileWriter
{
    public void write(String name)
    {
        System.out.println("保存文件"+name);
    }
}

class Facade
{
    private FileReader reader = new FileReader();
    private Encrypt encrypt = new Encrypt();
    private FileWriter writer = new FileWriter();

    public void fileEncrypt(String name)
    {
        reader.read(name);
        encrypt.encrypt(name);
        writer.write(name);
    }
}

这里的例子比较简单,其实就是将读取,加密以及保存操做用外观角色包装起来,方便客户端调用。

4 引入抽象外观类

4.1 为何须要引入抽象外观类?

在标准的外观模式结构中,若是须要增长,删除或修改外观类交互的子系统类,必须修改外观类或客户端的源代码,这将违背开闭原则,好比上面的例子中须要更换一种加密方法,也就是换一个加密类,这样须要直接修改外观类。

能够经过引入抽象外观类来解决该问题,引入后,客户端能够针对抽象外观类进行编程,对于新的业务需求不须要修改原有的外
观类,只须要新增一个对应的具体外观类便可。

4.2 如何引入?

首先定义抽象外观类,接着具体外观类继承或者实线抽象外观类便可。客户端针对抽象外观类进行编程,在运行时再肯定具体的外观类,好比在上面例子的基础上修改加密方法,首先定义抽象外观类(这里是接口,只有一个加密方法):

interface AbstractFacade
{
    void encrypt(String name);
}

接着定义具体外观类:

class Facade1 implements AbstractFacade
{
    private FileReader reader = new FileReader();
    private Encrypt1 encrypt1 = new Encrypt1();
    private FileWriter writer = new FileWriter();

    @Override
    public void encrypt(String name)
    {
        reader.read(name);
        encrypt1.encrypt(name);
        writer.write(name);
    }
}

class Facade2 implements AbstractFacade
{
    private FileReader reader = new FileReader();
    private Encrypt2 encrypt2 = new Encrypt2();
    private FileWriter writer = new FileWriter();

    @Override
    public void encrypt(String name)
    {
        reader.read(name);
        encrypt2.encrypt(name);
        writer.write(name);
    }
}

这两个类除了加密方法不同其余都同样,测试:

AbstractFacade facade = new Facade1();
facade.encrypt("111");
facade = new Facade2();
facade.encrypt("222");

引入抽象外观类后,客户端针对抽象外观类进行编程,运行时肯定具体外观类,输出以下:
设计模式学习笔记(十三):外观模式

5 注意事项

  • 外观单例:不少状况下为了节约系统资源,系统只须要一个外观类的实例,也就是外观类能够是一个单例类,这样能够下降系统资源的消耗
  • 多个外观类:在一个系统中能够设计多个外观类,每一个外观类负责和一些特定子对象交互,向客户端提供相应业务功能
  • 不要经过外观类增长新行为:外观模式的意图是为子系统提供一个集中简化的沟通渠道,而不是向子系统中增长新行为,新行为的增长应该经过修改原有子系统类或增长新的子系统类来实现而不是经过外观类实现

6 主要优势

  • 简化处理:对客户端屏蔽了子系统组件,减小了客户端所需处理的对象数目并使得子系统使用起来更加容易,引入外观模式后客户端代码将简化
  • 松耦合:实现了子系统于客户端之间松耦合关系,使得子系统的变化不会影响到客户端,只需修改外观类
  • 子系统修改灵活:一个子系统的修改对其余子系统没有影响,并且子系统内部变化也不会影响外观对象
  • 惟一入口:只提供了一个访问子系统的惟一入口,但不会影响客户端直接使用子系统类

7 主要缺点

  • 不能限制客户端使用子系统:外观模式不能很好地限制客户端直接使用子系统,若是客户端对访问子系统作太多的限制就会减小可变性与灵活性
  • 可能须要修改外观类:若是设计不当,增长新的子系统可能须要外观类,违背OCP

8 适用场景

  • 当要为访问一系列复杂的子系统提供一个简单的入口时
  • 客户端与多个子系统存在很大依赖性
  • 层次化结构中,能够使用外观模式定义系统中每一层的入口,层与层之间不直接产生联系,而经过外观类创建联系,下降层之间的耦合度

9 总结

设计模式学习笔记(十三):外观模式

若是以为文章好看,欢迎点赞。

同时欢迎关注微信公众号:氷泠之路。

在这里插入图片描述

相关文章
相关标签/搜索