模式定义
外观模式,又称为门面模式,是一种使用频率非常高的结构型设计模式,是迪米特法则的一种具体实现,它通过引入一个外观角色来简化客户端与子系统之间的交互,为复杂的子系统调用提供一个统一的入口,降低子系统与客户端的耦合度,且客户端调用非常方便。如下图:
举个例子:如网站导航
主要作用
- 实现客户类与子系统类的松耦合;
- 降低原有系统的复杂度;
- 提高了客户端使用的便捷性,使得客户端无须关心子系统的工作细节,通过外观角色即可调用相关功能。
UML类图
角色
外观角色(Facade):也称 门面角色,系统对外的统一接口;
子系统角色(SubSystem):可以同时有一个或多个 SubSystem。每个 SubSytem 都不是一个单独的类,而是一个类的集合。SubSystem 并不知道 Facade 的存在,对于 SubSystem 而言,Facade 只是另一个客户端而已(即 Facade 对 SubSystem 透明)。
外观模式的目的不是给予子系统添加新的功能接口,而是为了让外部减少与子系统内多个模块的交互,松散耦合,从而让外部能够更简单地使用子系统。
外观模式的本质是:封装交互,简化调用。
模式优点
降低了客户类与子系统类的耦合度,实现了子系统与客户之间的松耦合关系;
- 只是提供了一个访问子系统的统一入口,并不影响用户直接使用子系统类;
- 减少了与子系统的关联对象,实现了子系统与客户之间的松耦合关系,松耦合使得子系统的组件变化不会影响到它的客户。
外观模式对客户屏蔽了子系统组件,从而简化了接口,减少了客户处理的对象数目并使子系统的使用更加简单。
- 引入外观角色之后,用户只需要与外观角色交互;
- 用户与子系统之间的复杂逻辑关系由外观角色来实现。
降低原有系统的复杂度和系统中的编译依赖性,并简化了系统在不同平台之间的移植过程。
因为编译一个子系统一般不需要编译所有其他的子系统。一个子系统的修改对其他子系统没有任何影响,而且子系统内部变化也不会影响到外观对象。
模式缺点
不能很好地限制客户端直接使用子系统类,如果对客户端访问子系统类做太多的限制则减少了可变性和灵活性。
在不引入抽象外观类的情况下,增加新的子系统可能需要修改外观类或客户端的源代码,违背了“开闭原则”。
适用场景
- 为一个复杂的模块或子系统提供一个简洁的供外界访问的接口;
- 希望提高子系统的独立性时;
- 预防代码污染:当子系统由于不可避免的暂时原因导致可能存在 bug 或性能相关问题时,可以通过 外观模式 提供一个高层接口,隔离客户端与子系统的直接交互,方便后续问题修改;
- 在层次化结构中,可以使用外观模式定义系统中每一层的入口,层与层之间不直接产生联系,而通过外观类建立联系,降低层之间的耦合度。
使用步骤
创建外观角色
1 | package main.java.com.study.designPatterns.facade.demoOne; |
创建子系统
1 | package main.java.com.study.designPatterns.facade.demoOne; |
测试类
1 | package main.java.com.study.designPatterns.facade.demoOne; |
与适配模式的区别
外观模式的实现核心主要是——由外观类去保存各个子系统的引用,实现由一个统一的外观类去包装多个子系统类,然而客户端只需要引用这个外观类,然后由外观类来调用各个子系统中的方法。
这样的实现方式非常类似适配器模式,然而外观模式与适配器模式不同的是:适配器模式是将一个对象包装起来以改变其接口,而外观是将一群对象 ”包装“起来以简化其接口。它们的意图是不一样的,适配器是将接口转换为不同接口,而外观模式是提供一个统一的接口来简化接口。