一、外观模式的定义
外观(Facade)模式的定义:又叫门面模式,是一种通过为多个复杂的子系统提供一个一致的接口,而使这些子系统更加容易被访问的模式。该模式对外有一个统一接口,外部应用程序不用关心内部子系统的具体的细节,这样会大大降低应用程序的复杂度,提高了程序的可维护性。
二、外观模式优缺点
优点:
- 简化了调用过程,无需了解深入子系统,防止带来风险
- 减少系统依赖、松散耦合
- 更好的划分访问层次
- 符合迪米特法则,即最少知道原则
缺点:
- 增加子系统、扩展子系统行为容易引入风险
- 不符合开闭原则
三、外观模式的实现
外观(Facade)模式的结构比较简单,主要是定义了一个高层接口。它包含了对各个子系统的引用,客户端可以通过它访问各个子系统的功能。现在来分析其基本结构和实现方法。
外观(Facade)模式包含以下主要角色。
- 外观(Facade)角色:为多个子系统对外提供一个共同的接口。
- 子系统(Sub System)角色:实现系统的部分功能,客户可以通过外观角色访问它。
- 客户(Client)角色:通过一个外观角色访问各个子系统的功能。
其结构图如图所示:

代码常见有两种情况都是属于外观模式,如下代码:
所有子系统实现统一接口
public interface MySystem {
void dosomething();
}
// 子系统A
public class SubSystemA implements MySystem {
public void dosomething() {
System.out.println("子系统方法A");
}
}
// 子系统B
public class SubSystemB implements MySystem {
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();
}
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();
}
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