设计模式之适配器模式与外观模式(二)
- 2019 年 12 月 26 日
- 笔记
好了,通过上次的学习,我们已经知道适配器模式是如何将一个类的接口转换成另一个符合客户期望的接口。同时也知道在Java中要做到这一点,必须将一个不兼容接口的对象包装起来,变成兼容的对象。
我们现在要看一个改变接口的新模式,但是它改变接口的原因是为了简化接口。这个模式被巧妙地命名为外观模式(Facade-Pattern),之所以这么称呼,是因为它将一个或数个类的复杂的一切都隐藏在背后,只显露出一个干净美好的外观。
繁琐的看电影步骤
还记得我们之前说过的命令模式中,一个遥控器能控制很多家电的过程吧。简单的开关我们都会,复杂的模式,就比较麻烦,比如看电影的步骤:
- 打开爆米花机
- 开始爆米花
- 将灯光调暗
- 放下屏幕
- 打开投影机
- 将投影机的输入切换到DVD
- 将投影机设置在宽屏模式
- 打开功放
- 将功放的输入设置为DVD
- 将攻放设置为环绕立体声
- 将攻放音量调到中
- 打开DVD播放器
- 开始播放DVD
看一个电影,真的是如此繁琐。而且看完电影之后,还得过去把这些步骤都关闭。是用你的家庭影院竟然变得如此复杂!让我们看看外观模式如何解决这团混乱,好让你轻松享受。
灯光、相机、外观!
你需要的正是一个外观:有了外观模式,通过实现一个提供更合理的接口的外观类,你可以将一个复杂的子系统变得容易使用。
- 我们为家庭影院系统创建一个外观,命名为HomeTheaterFacade,它对外暴露出几个简单的方法,例如watchMovie()
- 这个外观类将家庭影院诸多组件视为一个子系统,通过调用这个子系统,来实现watchMovie()方法
- 现在,你的客户代码可以调用此家庭影院外观所提供的方法,而不必再调用这个子系统的方法。
- 外观只是提供你更直接的操作,并未将原来的子系统阻隔起来。如果你需要子系统类的更高层的功能呢,还是可以使用原来的子系统的
构造家庭影院外观
好了,那接下来就到实战阶段啦。
第一步是使用组合让外观能够访问子系统中所有的组件
public class HomeTheaterFacade { Amplifier amp; Tuner tuner; DvdPlayer dvd; CdPlayer cd; Projector projector; TheaterLights lights; Screen screen; PopcornPopper popper; public HomeTheaterFacade(Amplifier amp, Tuner tuner, DvdPlayer dvd, CdPlayer cd, Projector projector, Screen screen, TheaterLights lights, PopcornPopper popper) { this.amp = amp; this.tuner = tuner; this.dvd = dvd; this.cd = cd; this.projector = projector; this.screen = screen; this.lights = lights; this.popper = popper; } // 将我们之前手动进行的每项任务依次处理。这里每项任务都是委托子系统中相应的组件处理的 public void watchMovie(String movie) { System.out.println("Get ready to watch a movie..."); popper.on(); popper.pop(); lights.dim(10); screen.down(); projector.on(); projector.wideScreenMode(); amp.on(); amp.setDvd(dvd); amp.setSurroundSound(); amp.setVolume(5); dvd.on(); dvd.play(movie); } public void endMovie() { System.out.println("Shutting movie theater down..."); popper.off(); lights.on(); screen.up(); projector.off(); amp.off(); dvd.stop(); dvd.eject(); dvd.off(); } }
有了这个基础,后面观赏电影就变得简单了。
public class HomeTheaterTestDrive { public static void main(String[] args) { Amplifier amp = new Amplifier("Top-O-Line Amplifier"); Tuner tuner = new Tuner("Top-O-Line AM/FM Tuner", amp); DvdPlayer dvd = new DvdPlayer("Top-O-Line DVD Player", amp); CdPlayer cd = new CdPlayer("Top-O-Line CD Player", amp); Projector projector = new Projector("Top-O-Line Projector", dvd); TheaterLights lights = new TheaterLights("Theater Ceiling Lights"); Screen screen = new Screen("Theater Screen"); PopcornPopper popper = new PopcornPopper("Popcorn Popper"); // 根据子系统所有的组件来实例化外观 HomeTheaterFacade homeTheater = new HomeTheaterFacade(amp, tuner, dvd, cd, projector, screen, lights, popper); // 使用简化的接口,并开启电影,然后关闭电影 homeTheater.watchMovie("Raiders of the Lost Ark"); homeTheater.endMovie(); } }
就这样,我们完成了外观模式的处理。当你使用完,是不是觉得很简单了呢。
定义外观模式
想要用外观模式,我们创建了一个接口简化而统一的类,用来包装子系统中一个或多个复杂的类。外观模式相当直接,很容易理解,这方面和许多其他的模式不太一样。但这并不会降低它的威力:外观模式允许我们让客户和子系统之间避免紧耦合。而且外观模式也帮我们遵循一个新的面向对象原则。
外观模式提供了一个统一的接口,用来访问子系统中的一群接口。外观定义了一个高层接口,让子系统更容易使用。
最少知识原则:只和你的密友谈话。这个原则系统我们在设计中,不要让太多的类耦合在一起,免得修改系统中的一部分,会影响到其他部分。如果许多类之间相互依赖,那么这个系统就会变成一个易碎的系统,他需要花许多成本维护,也会因为太复杂而不容易被其他人了解。
我们来做一个对比大家就知道啦
// 不采用这个原则,我们需要调用两次方法才能获取到最终的信息 public float getTemp() { Thermometer thermometer = station.getThermometer(); return thermometer.getTemperature(); } // 采用这个原则,我们加进一个方法,这样就可以减少我们所依赖的类的数目 public float getTemp() { return station.getTemperature(); }
设计箱内的工具
因为这次学习的内容比较简单,我就在这篇里进行总结了。
- OO基础 抽象、封装、继承、多态
- OO原则 封装变化 多用组合,少用继承 针对接口编程,不针对实现编程 为交互对象之间的松耦合设计而努力 依赖抽象,不要依赖具体类 类应该对扩展开放,对修改关闭 只和朋友交谈
- OO模式 ‘策略模式’、‘观察者模式’、‘装饰者模式’、‘抽象工厂模式’、‘工厂方法模式’、‘单例模式’、‘命令模式’ ‘适配器模式’将一个类的接口,转换成客户期望另一个接口。适配器让原本不兼容的类合作无间。 ‘外观模式’提供了一个统一的接口,用来访问子系统中的一群接口。外观定义了一个高层接口,让子系统更容易使用。
这次学习的适配器和外观,虽然篇幅不多,但是在平常写代码的过程中还是经常使用的,尤其是适配器模式,你们觉得呢?所以,这一块还得巩固好,这样对于后面编写代码,理解代码的根源很有帮助的哦。下次,我们开启模板方式模式之旅。
PS:小编在介绍适配器模式的时候,只举例说明了对象适配器。其实还有一个类适配器,但是那个是需要用到多重继承的,考虑到Java没有实际场景,这里就略过了。感兴趣的朋友可以继续深入研究下。