1、简介
外观模式提供了一个统一的接口,用来访问子系统中的一群接口。外观定义了一个高层接口,让子系统更容易使用。
使用外观模式时,我们创建了一个统一的类,用来包装子系统中一个或多个复杂的类,客户端可以直接通过外观类来调用内部子系统中方法,从而外观模式让客户和子系统之间避免了紧耦合。
外观模式的目的不是为了给子系统添加新的功能接口,而是为了让外部减少与子系统内多个模块的交互,松散耦合,从而让外部能够更简单地使用子系统。
定义:为子系统中的一组接口提供一个一致的界面,外观模式定义了一个高层接口,这个接口使得这一子系统更加容易使用。
本质:封装交互,简化调用。
英文:Facade
类型:结构型模式
2、实例引入
背景:模仿安装智能家居前后的对比
操作灯光接口
package com.designpattern.facade; /** * 类说明 :灯光接口 */ public interface LightI { /** * 开灯 */ public void on(); /** * 关灯 */ public void off(); }
package com.designpattern.facade.impl; import com.designpattern.facade.LightI; /** * 类说明 :灯光接口实现类 */ public class Light implements LightI { @Override public void on() { System.out.println("打开灯"); } @Override public void off() { System.out.println("关闭灯"); } }
操作电视接口
package com.designpattern.facade; /** * 类说明 :电视接口 */ public interface TVI { /** * 开机 */ public void on(); /** * 关机 */ public void off(); }
package com.designpattern.facade.impl; import com.designpattern.facade.TVI; /** * 类说明 :电视接口实现类 */ public class TV implements TVI { @Override public void on() { System.out.println("打开电视"); } @Override public void off() { System.out.println("关闭电视"); } }
在安装智能家居前:
package com.designpattern.facade; import com.designpattern.facade.impl.Light; import com.designpattern.facade.impl.TV; /** * 类说明 :测试 */ public class Test { public static void main(String[] args) { //----晚上下班回到家---- //开灯光 LightI light = new Light(); light.on(); //看电视 TVI tv = new TV(); tv.on(); //-----睡觉----- //关灯光 light.off(); //关电视 tv.off(); } }
结果:
打开灯 打开电视 关闭灯 关闭电视
我们需要一个一个把需要开的电器打开,是不是好麻烦?
下面咱们引入智能家居
package com.designpattern.facade; /** * 类说明 :智能家居总开关接口 */ public interface SmartHomeI { /** * 总开 */ public void on(); /** * 总关 */ public void off(); }
package com.designpattern.facade.impl; import com.designpattern.facade.LightI; import com.designpattern.facade.SmartHomeI; import com.designpattern.facade.TVI; /** * 类说明 :智能家居总开关接口 */ public class SmartHome implements SmartHomeI { private LightI light = new Light(); private TVI tv = new TV(); @Override public void on() { light.on(); tv.on(); } @Override public void off() { light.off(); tv.off(); } }
安装智能家居以后:
package com.designpattern.facade; import com.designpattern.facade.impl.Light; import com.designpattern.facade.impl.SmartHome; import com.designpattern.facade.impl.TV; /** * 类说明 :测试 */ public class Test { public static void main(String[] args) { SmartHomeI smarthome = new SmartHome(); //----晚上下班回到家---- smarthome.on(); //-----睡觉----- smarthome.off(); } }
结果:
打开灯 打开电视 关闭灯 关闭电视
就一个开关是不是很方便?
3、解决的问题
从上面的例子看:
外观模式对客户屏蔽了子系统组件,从而简化了接口,减少了客户处理的对象数目并使子系统的使用更加简单。
外观模式实现了子系统与客户之间的松耦合关系,而子系统内部的功能组件是紧耦合的,松耦合使得子系统的组件变化不会影响到它的客户。(比如将来我换一台电视,只需要修改一下电视接口即可,对外部的智能家居接口不需要修改,从而不影响外部使用者)
4、应用场景
需要将设计进行分层时考虑外观模式;(在层次化结构中,可以使用外观模式定义系统中每一层的入口,其中三层架构就是这样的一个例子)
在开发阶段,子系统往往因为重构变得越来越复杂,增加外观模式可以提供一个简单的接口,减少它们之间的依赖;(外一个复杂的子系统提供一个简单的接口)
在维护一个遗留的大型系统时,可以这个系统已经非常难以维护和扩展,可以为新系统开发一个外观类,来提供设计粗糙或高度复杂的遗留代码的比较清晰简单的接口,让新系统与外观类交互,外观模式与遗留代码交互所有复杂的工作;(提供子系统的独立性)
5、优缺点
优点:
外观模式降低了客户端对子系统使用的复杂性;
外观模式松散了客户端与子系统的耦合关系,让子系统内部的模块能更容易扩展和维护;
通过合理使用外观模式,可以帮助我们更好的划分访问的层次;
使用外观模式还有一个附带的好处,就是能够有选择性地暴露方法。一个模块中定义的方法可以分成两部分,一部分是给子系统外部使用的,一部分是子系统内部模块之间相互调用时使用的。有了外观类,那么用于子系统内部模块之间相互调用的方法就不用暴露给子系统外部了;
缺点:
如果增加新的子系统可能需要修改外观类或客户端的源代码,这样就违背了”开——闭原则“(不过这点也是不可避免);
6、与其他模式对比
外观模式与适配器模式非常类似;
外观模式与适配器模式不同的是:适配器模式是将一个对象包装起来以改变其接口,而外观是将一群对象 ”包装“起来以简化其接口。它们的意图是不一样的,适配器是将接口转换为不同接口,而外观模式是提供一个统一的接口来简化接口;
外观模式旨在:子系统的高层接口;
适配器模式旨在:对象接口的变化;
7、总结
外观模式,为子系统的一组接口提供一个统一的接口,该模式定义了一个高层接口,这一个高层接口使的子系统更加容易使用。并且外观模式可以解决层结构分离、降低系统耦合度和为新旧系统交互提供接口功能。
PS:源码地址 https://github.com/JsonShare/DesignPattern/tree/master
PS:原文地址 http://www.cnblogs.com/JsonShare/p/7121383.html