外观模式
外观模式
对象结构型模式

模式动机
外观模式可以为系统提供不同类型的子对象选择

引入外观角色后,用户只要和外观角色交互,用户与每个子系统之间的复杂关系都由外观角色来实现,解耦用户和子系统。

应用
外部用户与一个子系统的通信必须通过一个统一的外观对象进行,为子系统中对外暴露的接口提供一个一致的界面(即调用方式);外观模式定义了一个高层接口,这个接口使子系统更加容易使用。
外观对象包含如下角色:
- 外观角色Facade
- 子系统角色SubSystem
根据单一职责原则,软件系统中存在若干子系统是正常的现象,这有利于降低整个系统的复杂度。既然大家都是单一职责的且系统中存在很多子系统,那么彼此之间需要通信,一个常见的设计目标是使子系统间的通信和相互依赖关系达到最小,达到这一目标常用的途径之一就是引入一个外观对象,它为访问子系统提供一个简单唯一的入口。
同时,用户(子系统外部)与内部通信也只需要通过统一的外观对象进行,外观类将客户端与子系统内部的复杂性隔开,使用户不需要与子系统内部很多对象打交道。这样封装了子系统的内部实现细节,用户无需关心具体实现,通过外观角色即可调用功能。
这也是迪米特法则的体现,用户与子系统之间不必直接通信,而都是和外观对象“做朋友”。
典型外观角色代码如下:
public class Facade { |
实例:电源总开关
为了使用方便,一个电源总开关可以控制四盏灯、一个风扇、一台空调和一台电视机等所有设备的启动和关闭。

实例:文件加密
某系统需要提供一个文件加密模块,加密流程包括三个操作,分别是读取源文件、加密、保存加密之后的文件。读取文件和保存文件使用流来实现,这三个操作相对独立,其业务代码封装在三个不同的类中。现在需要提供一个统一的加密外观类,用户可以直接使用该加密外观类完成文件的读取、加密和保存三个操作,而不需要与每一个类进行交互。

从上面这两个实例可以看出,外观模式更像是一个被委托人,负责接取用户的委托,代为执行一系列操作(访问子系统中的对象),并返回结果
优点
- 对客户屏蔽子系统组件,减少了客户处理的对象数目并使子系统的使用更容易,并且由于与客户直接关联的对象很少,客户代码也变得很简单
- 客户端和子系统之间是松耦合的,子系统的变化不会影响到客户端,只需要调整外观类
- 降低了编译依赖性,因为子系统之间的直接依赖减少了,一个子系统的编译一般不需要其他子系统,所以修改一个子系统重新编译的时候不会影响其他子系统
- 只是额外提供了一个访问子系统的统一入口,并不影响用户仍然坚持直接使用子系统类
缺点
- 如上优点4,这也是一个缺点,封装的不彻底,用户还是能直接用子系统类,还是有可能产生直接耦合
- 由于外观模式中没有任何抽象类或接口,全是面向具体实现编程的,所以添加新的子系统需要修改外观类的具体原有代码,违反开闭原则
适用场合
- 需要为一个复杂子系统集合提供一个统一调用的简单接口,比如一口气调用一遍所有子系统的某个方法
- 用户程序与多个子系统之间存在很大的依赖性。引入外观类解耦用户程序和子系统,可以提高子系统的独立性和可移植性
- 在层次化结构中,用外观模式定义一层的入口,使得层与层之间不产生直接耦合,上层/下层调用下层/上层时直接通过外观类,不必在层与层之间产生复杂的联系
Session外观模式是外观模式在Java EE框架中的应用

模式扩展
一个系统多个外观类
一般而言一个系统只有一个外观类,且通常是单例的;但一个系统也可以设计多个外观类,每个外观类负责和一部分子系统交互,从而对外提供不同的操作组合
警告:不要通过外观类为子系统增加新行为
不要试图继承外观类来在子系统中加入新的行为,这是错误的。外观模式的本意是为子系统提供一个集中且简化的通信/调用接口,而非扩展其行为。
外观模式与迪米特法则
如题,外观模式是迪米特法则的一个很好的运用,在一个软件系统中,如果用户频繁地直接调用子系统的相似接口做重复的操作,就可以用外观模式来重构以实现迪米特法则。
抽象类的引入
为了符合开闭原则。引入抽象外观类后,对于新的业务需求,不修改原有外观类,而对应增加一个新的具体外观类,由新的具体外观类来关联新的子系统对象,同时通过修改配置文件来达到不修改源代码并更换外观类的目的。

(•‿•)