内功心法专题-设计模式-11、外观模式
1. 模式定义
外观模式(Facade),也叫门面模式,也叫过程模式。是“迪米特法则”的典型应用。
外观模式为子系统中的一组接口提供一个一致的界面,此模式定义了一个高层接口,用以屏蔽内部子系统的细节,使得调用端只需跟这个接口发生调用,而无需关心这个子系统的内部细节,这个接口使得这一子系统更加容易使用❕
2. 模式结构
2.1. 模式角色
外观(Facade)模式包含以下主要角色:
- 外观(Facade)角色:为多个子系统对外提供一个共同的接口。
- 子系统(Sub System)角色:实现系统的部分功能,客户可以通过外观角色访问它。
2.2. UML图示
2.3. 实现逻辑⭐️🔴
聚合:外观类聚合子系统类
3. 案例分析
3.1. 影院管理项目
DVD 播放器、投影仪、自动屏幕、环绕立体声、爆米花机,要求完成使用家庭影院的功能,其过程为:
- 直接用遥控器:统筹各设备开关
- 开爆米花机
- 放下屏幕
- 开投影仪
- 开音响
- 开DVD,选dvd
- 去拿爆米花
- 调暗灯光
- 播放
- 观影结束后,关闭各种设备
3.1.1. 传统方案
传统方式解决影院管理问题分析
- 1)在 ClientTest 的 main 方法中,创建各个子系统的对象,并直接去调用子系统(对象)相关方法,会造成调用过程混乱,没有清晰的过程
- 2)不利于在 ClientTest 中去维护对子系统的操作
- 3)解决思路:定义一个高层接口,给子系统中的一组接口提供一个一致的界面(比如在高层接口提供四个方法ready,play,pause,end),用来访问子系统中的一群接口
- 4)也就是说就是通过定义一个一致的接口(界面类),用以屏蔽内部子系统的细节,使得调用端只需跟这个接口发生调用,而无需关心这个子系统的内部细节
3.1.2. 外观模式
3.2. 智能家电控制
通过智能音箱,语音直接控制这些智能家电的开启和关闭
4. 优缺点⭐️🔴
优点:
- 降低了子系统与客户端之间的耦合度,使得子系统的变化不会影响调用它的客户类。
- 对客户屏蔽了子系统组件,减少了客户处理的对象数目,并使得子系统使用起来更加容易。
缺点:
- 不符合开闭原则,修改很麻烦:如果子系统有变更,客户端不需要修改,但是Facade类需要做相应的修改。
❕
5. 适用场景⭐️🔴
- 对于系统内部而言:对分层结构系统构建时,使用外观模式定义子系统中每层的入口点可以简化子系统之间的依赖关系。
- 对于系统边缘而言:当一个复杂系统的子系统很多时,外观模式可以为系统设计一个简单的接口供外界访问
- 对于客户端而言:当客户端与多个子系统之间存在很大的联系时,引入外观模式可将它们分离,从而提高子系统的独立性和可移植性。
6. JDK源码分析
6.1. Tomcat RequestFacade
使用tomcat作为web容器时,接收浏览器发送过来的请求,tomcat会将请求信息封装成ServletRequest对象,如下图①处对象。但是大家想想ServletRequest是一个接口,它还有一个子接口HttpServletRequest,而我们知道该request对象肯定是一个HttpServletRequest对象的子实现类对象,到底是哪个类的对象呢?可以通过输出request对象,我们就会发现是一个名为RequestFacade的类的对象。
RequestFacade类就使用了外观模式。先看结构图:
为什么在此处使用外观模式呢?
定义 RequestFacade 类,实现 ServletRequest ,同时定义私有成员变量 Request ,并且方法的实现调用 Request 的实现。然后,将 RequestFacade上转为 ServletRequest 传给 servlet 的 service 方法,这样即使在 servlet 中被下转为 RequestFacade ,也不能访问私有成员变量对象中的方法。既用了 Request ,又能防止其中方法被不合理的访问。
6.2. MyBatis 框架源码分析
7. 实战经验
- 1)外观模式对外屏蔽了子系统的细节,因此外观模式降低了客户端对子系统使用的复杂性
- 2)外观模式对客户端与子系统的耦合关系,让子系统内部的模块更易维护和扩展
- 3)通过合理的使用外观模式,可以帮我们更好的划分访问的层次
- 4)当系统需要进行分层设计时,可以考虑使用 Facade 模式
- 5)在维护一个遗留的大型系统时,可能这个系统已经变得非常难以维护和扩展,此时可以考虑为新系统开发一个 Facade 类,来提供遗留系统的比较清晰简单的接口,让新系统与 Facade 类交互,提高复用性
- 6)不能过多的或者不合理的使用外观模式,使用外观模式好,还是直接调用模块好。要以让系统有层次,利于维护为目的