定义
为子系统中的一组接口提供一个一致的界面,Facade 模式定义了一个高层接口,这个接口是的这一子系统更加容易使用。
结构和说明
示例代码
public class FacadeDemo {
public static interface AModleApi {
void testA();
}
public static interface BModleApi {
void testB();
}
public static interface CModleApi {
void testC();
}
public static class AModleImpl implements AModleApi {
@Override
public void testA() {
System.out.println("现在在 A 模块操作 testA 方法");
}
}
public static class BModleImpl implements BModleApi {
@Override
public void testB() {
System.out.println("现在在 B 模块操作 testB 方法");
}
}
public static class CModleImpl implements CModleApi {
@Override
public void testC() {
System.out.println("现在在 C 模块操作 testC 方法");
}
}
public static class Facade {
public void test() {
AModleApi a = new AModleImpl();
BModleApi b = new BModleImpl();
CModleApi c = new CModleImpl();
a.testA();
b.testB();
c.testC();
}
}
public static class Client {
public static void main(String[] args) {
Facade facade = new Facade();
facade.test();
}
}
}
调用顺序
优缺点
优点
- 松散耦合
外观模式松散了客户端与子系统的耦合关系,让子系统的内部模块能够更加的扩展和维护。
- 简单易用
外观模式让子系统更加易用,客户端不再需要了解子系统内部的实现,也不需要跟众多子系统内部模块进行交互,只需要跟外观进行交互就可以了,相当于外观类为外部客户端使用子系统提供了一站式服务。
- 更好的划分访问层次
通过合理的使用 Facade,可以帮助我们更好的划分访问的层次。有些方法是对系统外的,有些方法是系统内部使用的。把需要暴露给外部的功能集中到外观中,这样既方便客户端使用,也很好的隐藏了内部的细节。
缺点
过多或者不太合理的 Facade 容易让人迷惑,到底是调用 Facade 好呢,还是直接调用模块好呢。
思考
本质
封装交互,简化调用。
对设计原则的体现
- 最少知道原则
何时选用
- 如果你希望为一个子复杂系统提供一个简单的接口的时候,可以考虑使用外观模式。使用外观模式实现大部分客户需要的功能,从而简化客户使用。
- 如果想要客户程序和抽象类的实现部分松散耦合,可以考虑使用外观模式,使用外观对象将这个子系统和客户分离开来,从而提供子系统的独立性和可移植性。
- 如果构建多层结构的程序,可以考虑使用外观模式,使用外观模式作为每层的入口,从而简化层间调用,也可以松散层次之间的依赖关系。
相关模式
- 外观模式和中介模式
这两个模式非常类似,但是却又本质区别。
中介者模式主要用来封装多个对象之间相互的交互 ,多用在系统内部的多个模块之间;而外观模式封装的是单向的交互,是从客户端访问系统的调用,没有从系统中来访问客户端的调用。
在中介者模式的实现里面 ,是需要实现具体的交互功能的;而外观模式的实现里面,一般是组合调用或者转调内部实现的功能,通过外观模式本身并不实现这些功能。
中介者模式的目的主要是松散多个模块的耦合 ,把这些耦合关系全部放到中介者中去实现;而外观模式的目的是简化客户端的调用,这点和中介者模式也不同。
- 外观模式和单例模式
通常一个子系统只需要一个外观实例,所以外观模式可以和单例模式组合使用,把 Facade 类实现成为单例 。当然,也可以跟前面的实例那样,把外观类的构造私有化,然后把提供给客户端的方法实现成为静态的。
- 外观模式和抽象工厂模式
外观模式的外观类通常需要和系统内部的多个模块交互,每个模块一般都有自己的接口, 所以在外观类的具体实现里面 ,需要获取这些接口,然后组合这些接口来完成客户端的功能。
那么怎么获取这些接口呢?就可以和抽象工厂一起使用,外观类通过抽象工厂来获取所需要的接口,而抽象工厂也可以把模块内部的实现对 Facade 进行屏蔽,也就是说 Facade 也仅仅知道它从模块中获取它需要的功能,模块内部的细节,Facade 也不知道。