12-外观模式

  1. 一、外观模式的定义
  2. 二、外观模式优缺点
  3. 三、外观模式的实现
  4. 四、外观模式的应用场景
  5. 五、外观模式的扩展
  6. 六、外观模式的注意事项和细节

一、外观模式的定义

外观(Facade)模式的定义:又叫门面模式,是一种通过为多个复杂的子系统提供一个一致的接口,而使这些子系统更加容易被访问的模式。该模式对外有一个统一接口,外部应用程序不用关心内部子系统的具体的细节,这样会大大降低应用程序的复杂度,提高了程序的可维护性。

二、外观模式优缺点

优点:

  • 简化了调用过程,无需了解深入子系统,防止带来风险
  • 减少系统依赖、松散耦合
  • 更好的划分访问层次
  • 符合迪米特法则,即最少知道原则

缺点:

  • 增加子系统、扩展子系统行为容易引入风险
  • 不符合开闭原则

三、外观模式的实现

外观(Facade)模式的结构比较简单,主要是定义了一个高层接口。它包含了对各个子系统的引用,客户端可以通过它访问各个子系统的功能。现在来分析其基本结构和实现方法。

外观(Facade)模式包含以下主要角色。

  • 外观(Facade)角色:为多个子系统对外提供一个共同的接口。
  • 子系统(Sub System)角色:实现系统的部分功能,客户可以通过外观角色访问它。
  • 客户(Client)角色:通过一个外观角色访问各个子系统的功能。

其结构图如图所示:

外观模式结构图

代码常见有两种情况都是属于外观模式,如下代码:

所有子系统实现统一接口

public interface MySystem {
    void dosomething();
}


// 子系统A
public class SubSystemA implements MySystem {
    @Override
    public void dosomething() {
        System.out.println("子系统方法A");
    }
}


// 子系统B
public class SubSystemB implements MySystem {
    @Override
    public void dosomething() {
        System.out.println("子系统方法B ");
    }
}


// 外观类
public class Facade {
    private SubSystemA systemA;
    private SubSystemB systemB;

    public Facade() {
        this.systemA = new SubSystemA();
        this.systemB = new SubSystemB();
    }

    public void methodA() {
        systemA.dosomething();
    }

    public void methodB() {
        systemB.dosomething();
    }
}


// 测试类
public class Client {
    public static void main(String[] args) {
        Facade facade = new Facade();
        facade.methodA();
        facade.methodB();
    }
}

运行结果:

子系统方法A
子系统方法B

所有子系统未实现统一接口

// 子系统A
public class SubSystemA {
    public void dosomething() {
        System.out.println("子系统方法AA");
    }
}


// 子系统B
public class SubSystemB {
    public void dosomething() {
        System.out.println("子系统方法BB ");
    }
}


// 外观类
public class Facade {
    private SubSystemA systemA;
    private SubSystemB systemB;

    public Facade() {
        this.systemA = new SubSystemA();
        this.systemB = new SubSystemB();
    }

    public void methodA() {
        this.systemA.dosomething();
    }

    public void methodB() {
        this.systemB.dosomething();
    }
}


// 测试类
public class Client {
    public static void main(String[] args) {
        Facade facade = new Facade();
        facade.methodA();
        facade.methodB();
    }
}

运行结果:

子系统方法AA
子系统方法BB

四、外观模式的应用场景

通常在以下情况下可以考虑使用外观模式。

  • 子系统越来越复杂,增加外观模式提供简单接口调用
  • 构建多层系统结构,利用外观对象作为每层的入口,简化层间调用

五、外观模式的扩展

在外观模式中,当增加或移除子系统时需要修改外观类,这违背了“开闭原则”。如果引入抽象外观类,则在一定程度上解决了该问题,其结构图如图所示:

引入抽象外观类

代码如下:

// 抽象外观类
public interface Facade {

    void method();
}

// 具体外观类A
public class FacadeImplA implements Facade {

    SubSystem1 subSystem1 = null;
    SubSystem2 subSystem2 = null;
    SubSystem3 subSystem3 = null;

    public FacadeImplA() {
        subSystem1 = new SubSystem1();
        subSystem2 = new SubSystem2();
        subSystem3 = new SubSystem3();
    }

    @Override
    public void method() {
        subSystem1.method1();
        subSystem2.method2();
        subSystem3.method3();
    }
}

// 具体外观类B
public class FacadeImplB implements Facade {

    SubSystem2 subSystem2 = null;
    SubSystem3 subSystem3 = null;
    SubSystem4 subSystem4 = null;

    public FacadeImplB() {
        subSystem2 = new SubSystem2();
        subSystem3 = new SubSystem3();
        subSystem4 = new SubSystem4();
    }

    @Override
    public void method() {
        subSystem2.method2();
        subSystem3.method3();
        subSystem4.method4();
    }
}

// 子系统类1
public class SubSystem1 {
    public void method1() {
        System.out.println("子系统1的method1()被调用!");
    }
}

// 子系统类2
public class SubSystem2 {
    public void method2() {
        System.out.println("子系统2的method2()被调用!");
    }
}

// 子系统类3
public class SubSystem3 {
    public void method3() {
        System.out.println("子系统3的method3()被调用!");
    }
}

// 子系统类4
public class SubSystem4 {
    public void method4() {
        System.out.println("子系统4的method4()被调用!");
    }
}

// 测试类
public class Client {
    public static void main(String[] args) {
        Facade facade1 = new FacadeImplA();
        facade1.method();

        Facade facade2 = new FacadeImplB();
        facade2.method();
    }
}

运行结果:

子系统1的method1()被调用!
子系统2的method2()被调用!
子系统3的method3()被调用!
子系统2的method2()被调用!
子系统3的method3()被调用!
子系统4的method4()被调用!

六、外观模式的注意事项和细节

  • 外观模式对外屏蔽了子系统的细节,因此外观模式降低了客户端对子系统使用的复杂性
  • 外观模式对客户端与子系统的耦合关系 - 解耦,让子系统内部的模块更易维护和扩展
  • 通过合理的使用外观模式,可以帮我们更好的划分访问的层次
  • 当系统需要进行分层设计时,可以考虑使用Facade 模式
  • 在维护一个遗留的大型系统时,可能这个系统已经变得非常难以维护和扩展,此时可以考虑为新系统开发一个 Facade 类,来提供遗留系统的比较清晰简单的接口,让新系统与 Facade 类交互,提高复用性。
  • 不能过多的或者不合理的使用外观模式,使用外观模式好,还是直接调用模块好。要以让系统有层次,利于维 护为目的。

转载请注明来源,欢迎对文章中的引用来源进行考证,欢迎指出任何有错误或不够清晰的表达。可以在下面评论区评论,也可以邮件至 george_95@126.com