外观模式
外观模式的概念
外观模式(Facade),也叫“过程模式“。外观模式为子系统中的一组接口提供一个一致的界面,此模式定义了一个高层接口,这个接口使得这一子系统更加容易使用。
外观模式通过定义一个一致的接口,用以屏蔽内部子系统的细节,使得调用端只需跟这个接口发生调用,而无需关心这个子系统的内部细节。
生活实例
比如说食堂的盘装套饭,一个盘子四个坑,一个装米饭,另外三个搭配不同的菜式。
解决的问题
假如有如下模块中的5个基础功能,对外封装成接口:
(图来源于漫画:设计模式之 “外观模式” )
如果有一个需求,需要先调用接口1再调用接口2最后调用接口5。
后面又有需求,需要按照顺序先调用接口4,再调用接口2,最后调用接口5。
发现很麻烦,因为需求在不断变更,那么调用的内容也会变更。
解决方法如下:
(图来源于漫画:设计模式之 “外观模式” )
将需要的接口组合成一个大的接口,大接口中包含子功能接口。
UML图
外观模式包含如下两个角色:
(1) Facade(外观角色):在客户端可以调用它的方法,在外观角色中可以知道相关的(一个或者多个)子系统的功能和责任;在正常情况下,它将所有从客户端发来的请求委派到相应的子系统去,传递给相应的子系统对象处理。
(2) SubSystem(子系统角色):在软件系统中可以有一个或者多个子系统角色,每一个子系统可以不是一个单独的类,而是一个类的集合,它实现子系统的功能;每一个子系统都可以被客户端直接调用,或者被外观角色调用,它处理由外观类传过来的请求;子系统并不知道外观的存在,对于子系统而言,外观角色仅仅是另外一个客户端而已。
注意:子类中没有Facade的任何信息,即没有对Facade对象的引用。
示例
调用关系是:客户端类Client调用外观类Facade,外观类组合子系统类SubSystemA、SubSystemB.......
首先是子系统类SubSystemA、SubSystemB等。
public class SubSystemA {
public void methodA() {
System.out.println("调用SubSystemA类的methodA()方法!");
}
}
接着是外观类Facade,对子系统接口的组合。
public class Facade {
private SubSystemA ssa=new SubSystemA();
private SubSystemB ssb=new SubSystemB();
private SubSystemC ssc=new SubSystemC();
private SubSystemD ssd=new SubSystemD();
private SubSystemE sse=new SubSystemE();
public void comboMethodA(){
// 封装一个子接口
ssa.methodA();
ssd.methodD();
sse.methodE();
}
public void comboMethodB(){
// 再封装一个子接口
ssb.methodB();
sse.methodE();
ssc.methodC();
}
}
最后是客户端类Client,调用外观类的组合接口方法。
public class Client {
public static void main(String[] args) {
// 不需要知道子系统有几个接口,只需要外观类的组合接口即可。
// 实例化外观类Facade
Facade facade = new Facade();
// 通过外观模式,调用组合接口A
facade.comboMethodA();
// 通过外观模式,调用组合接口B
facade.comboMethodB();
/* ------------------------下面是不使用外观模式,直接调用子系统类的代码----------------------- */
// 相当于调用comboMethodA()
SubSystemA ssa = new SubSystemA();
ssa.methodA();
SubSystemD ssd = new SubSystemD();
ssd.methodD();
SubSystemE sse = new SubSystemE();
sse.methodE();
// 相当于调用comboMethodB()
SubSystemB ssb = new SubSystemB();
ssb.methodB();
sse.methodE();
SubSystemC ssc = new SubSystemC();
ssc.methodC();
}
}
外观模式的总结
外观模式的优点:
- 降低了子系统与客户端之间的耦合度,使得子系统的变化不会影响调用它的客户类。(因为Client只需要调用Facade类中的方法,不需要直接调用子系统类了)
- 对客户屏蔽了子系统组件,减少了客户处理的对象数目,并使得子系统使用起来更加容易。
- 降低了大型软件系统中的编译依赖性,简化了系统在不同平台之间的移植过程,因为编译一个子系统不会影响其他的子系统,也不会影响外观对象。
外观模式的缺点:
- 不能很好地限制客户使用子系统类,很容易带来未知风险。
- 增加新的子系统可能需要修改外观类或客户端的源代码,违背了“开闭原则”。
外观模式的应用场景:
- 在设计功能接口的初期,有意识的将不同的层分离开,比如在数据访问层和业务逻辑层、业务逻辑层和表示层的层与层之间建立外观类Facade,降低耦合。
- 在开发阶段,子系统因为不断演化而变得越来越复杂,可以增加外观类Facade提供一个简单的接口,减少它们之间的依赖。
- 在维护一个遗留的系统时,较难以维护,但又包含重要功能,新的需求必须要依赖它,可以为新系统开发一个外观类Facade,提供接口,通过新系统与Facade对象、Facade对象与遗留系统代码完成新系统与旧系统的交互工作。
总结:外观模式就是子系统的组合使用。
参考链接: