设计模式笔记 - 外观模式(Facade Pattern)

模式定义

外观模式(Facade Pattern):外部与一个子系统的通信必须通过一个统一的外观对象进行,为子系统中的一组接口提供一个一致的界面,外观模式定义了一个高层接口,这个接口使得这一子系统更加容易使用。


模式结构

外观模式包含如下角色:

  • Facade:外观角色
  • SubSystem:子系统角色

img


模式实例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
/*
* 此例通过外观模式设计的门面,整合了三个子系统的接口并依次调用。
*/
// SubSystem - 子系统角色
// 子系统A
public class SystemA {

public void operationA() {
System.out.println("This is operationA!");
}
}

// 子系统B
public class SystemB {

public void operationB() {
System.out.println("This is operationB!");
}
}

// 子系统C
public class SystemC {

public void operationC() {
System.out.println("This is operationC!");
}
}

// 外观角色
public class Facade {
SystemA systemA = new SystemA();
SystemB systemB = new SystemB();
SystemC systemC = new SystemC();

public void warpOperation() {
systemA.operationA();
systemB.operationB();
systemC.operationC();
}
}

// Client - 客户端类
public class Client {
public static void main(String[] args) {
Facade facade = new Facade();
facade.warpOperation();
}
}

模式分析

  • 根据“单一职责原则”,在软件中将一个系统划分为若干个子系统有利于降低整个系统的复杂性,一个常见的设计目标是使子系统间的通信与互相依赖关系达到最小,而达到该目标的途径之一就是引入一个外观对象,它为子系统的访问提供了一个简单而单一的接口。
  • 外观模式要求一个子系统的外部与其内部的通信通过一个统一的外观对象进行,外观类将客户端与子系统的内部复杂性分隔开,使得客户端只需要与外观对象打交道,无需关注内部复杂的细节,提高客户的使用体验。

外观模式的优点:

  • 对客户屏蔽了子系统的组件,减少客户处理的对象数目,也使得子系统使用起来更加容易。
  • 同时也封装了子系统内部细节,降低了客户与子系统之间的耦合。
  • 外观模式只是提供了一个访问子系统的统一入口,但是并不影响用户直接操作子系统(如果允许的情况下)。

外观模式的缺点:

  • 不能很好地限制客户使用子系统类,如果对客户过多的访问子系统类,则会间接增加了客户与子系统类的耦合程度,减少了灵活性。
  • 在不引入抽象外观类的情况下,增加新的子系统可能需要修改外观类或客户端源代码,违背了“开闭原则”。

注意点:

  • 不要通过继承外观类在子系统中加入新的行为。因为外观模式的本质在于为子系统提供一个集中化的、更加简化的接口,而不是向子系统中添加新的行为,而导致增加系统的复杂度。
  • 外观模式最大的缺点在于违背了“开闭原则”,当增加新的子系统或者移除子系统时需要修改外观类,可以通过引入抽象外观类在一定程度上解决该问题,客户端针对抽象外观类进行编程。对于新的业务需求,不修改原有外观类,而对应增加一个新的具体外观类,由新的具体外观类来关联新的子系统对象,同时通过修改配置文件来达到不修改源代码并更换外观类的目的。


参考资料:

[1] https://design-patterns.readthedocs.io/zh_CN/latest/structural_patterns/facade.html