定义

为子系统中的一组接口提供一个一致的界面,Facade 模式定义了一个高层接口,这个接口是的这一子系统更加容易使用。

结构和说明

结构型模式-外观模式 - 图1

示例代码

  1. public class FacadeDemo {
  2. public static interface AModleApi {
  3. void testA();
  4. }
  5. public static interface BModleApi {
  6. void testB();
  7. }
  8. public static interface CModleApi {
  9. void testC();
  10. }
  11. public static class AModleImpl implements AModleApi {
  12. @Override
  13. public void testA() {
  14. System.out.println("现在在 A 模块操作 testA 方法");
  15. }
  16. }
  17. public static class BModleImpl implements BModleApi {
  18. @Override
  19. public void testB() {
  20. System.out.println("现在在 B 模块操作 testB 方法");
  21. }
  22. }
  23. public static class CModleImpl implements CModleApi {
  24. @Override
  25. public void testC() {
  26. System.out.println("现在在 C 模块操作 testC 方法");
  27. }
  28. }
  29. public static class Facade {
  30. public void test() {
  31. AModleApi a = new AModleImpl();
  32. BModleApi b = new BModleImpl();
  33. CModleApi c = new CModleImpl();
  34. a.testA();
  35. b.testB();
  36. c.testC();
  37. }
  38. }
  39. public static class Client {
  40. public static void main(String[] args) {
  41. Facade facade = new Facade();
  42. facade.test();
  43. }
  44. }
  45. }

调用顺序

结构型模式-外观模式 - 图2

优缺点

优点

  • 松散耦合

外观模式松散了客户端与子系统的耦合关系,让子系统的内部模块能够更加的扩展和维护。

  • 简单易用

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

  • 更好的划分访问层次

通过合理的使用 Facade,可以帮助我们更好的划分访问的层次。有些方法是对系统外的,有些方法是系统内部使用的。把需要暴露给外部的功能集中到外观中,这样既方便客户端使用,也很好的隐藏了内部的细节。

缺点

过多或者不太合理的 Facade 容易让人迷惑,到底是调用 Facade 好呢,还是直接调用模块好呢。

思考

本质

封装交互,简化调用。

对设计原则的体现

  • 最少知道原则

何时选用

  • 如果你希望为一个子复杂系统提供一个简单的接口的时候,可以考虑使用外观模式。使用外观模式实现大部分客户需要的功能,从而简化客户使用。
  • 如果想要客户程序和抽象类的实现部分松散耦合,可以考虑使用外观模式,使用外观对象将这个子系统和客户分离开来,从而提供子系统的独立性和可移植性。
  • 如果构建多层结构的程序,可以考虑使用外观模式,使用外观模式作为每层的入口,从而简化层间调用,也可以松散层次之间的依赖关系。

相关模式

  • 外观模式和中介模式

这两个模式非常类似,但是却又本质区别。
中介者模式主要用来封装多个对象之间相互的交互 ,多用在系统内部的多个模块之间;而外观模式封装的是单向的交互,是从客户端访问系统的调用,没有从系统中来访问客户端的调用。
在中介者模式的实现里面 ,是需要实现具体的交互功能的;而外观模式的实现里面,一般是组合调用或者转调内部实现的功能,通过外观模式本身并不实现这些功能。
中介者模式的目的主要是松散多个模块的耦合 ,把这些耦合关系全部放到中介者中去实现;而外观模式的目的是简化客户端的调用,这点和中介者模式也不同。

  • 外观模式和单例模式

通常一个子系统只需要一个外观实例,所以外观模式可以和单例模式组合使用,把 Facade 类实现成为单例 。当然,也可以跟前面的实例那样,把外观类的构造私有化,然后把提供给客户端的方法实现成为静态的。

  • 外观模式和抽象工厂模式

外观模式的外观类通常需要和系统内部的多个模块交互,每个模块一般都有自己的接口, 所以在外观类的具体实现里面 ,需要获取这些接口,然后组合这些接口来完成客户端的功能。
那么怎么获取这些接口呢?就可以和抽象工厂一起使用,外观类通过抽象工厂来获取所需要的接口,而抽象工厂也可以把模块内部的实现对 Facade 进行屏蔽,也就是说 Facade 也仅仅知道它从模块中获取它需要的功能,模块内部的细节,Facade 也不知道。