java设计模式之外观模式
一.外观模式原理
1.一个家庭影院项目
DVD播放器、投影仪、自动屏幕、环绕立体声、爆米花机
2.传统的控制接口设计
直接用遥控器:统筹各设备开关(开爆米花机、放下屏幕、开投影仪、开音响、开DVD选DVD,去拿爆米花、调暗灯光、播放、观影结束后关闭各种设备)
3.外观模式的原理和设计
把所有的功能或类似功能放到一个按钮上,如一个Ready调用下面的所有开始方法。外观模式就是在所有这些接口的上层再绘制一个遥控器,把原来这个系统里面每个对象、类的接口调用统筹起来,分组打包。
外观模式:提供一个统一的接口,来访问子系统中一群功能相关接口。
外观模式定义了一个高层接口,让子系统更容易使用。
实例:
DVDPlayer.java
package com.bijian.study.facade.hometheater; /** * DVD播放器类 * @author bijian * */ public class DVDPlayer { private static DVDPlayer instance = null; private DVDPlayer() { } public static DVDPlayer getInstance() { if (instance == null) { instance = new DVDPlayer(); } return instance; } public void on() { System.out.println("DVDPlayer On"); } public void off() { System.out.println("DVDPlayer Off"); } public void play() { System.out.println("DVDPlayer is playing"); } public void pause() { System.out.println("DVDPlayer pause"); } public void setdvd() { System.out.println("DVDPlayer is setting dvd"); } }
Popcorn.java
package com.bijian.study.facade.hometheater; /** * 爆米花类 * @author bijian * */ public class Popcorn { private static Popcorn instance = null; private Popcorn() { } public static Popcorn getInstance() { if (instance == null) { instance = new Popcorn(); } return instance; } //打开 public void on() { System.out.println("Popcorn On"); } //关闭 public void off() { System.out.println("Popcorn Off"); } //爆米花 public void pop() { System.out.println("Popcorn is popping"); } }
Projector.java
package com.bijian.study.facade.hometheater; /** * 投影仪类 * @author bijian * */ public class Projector { private int size=5; private static Projector instance = null; private Projector() { } public static Projector getInstance() { if (instance == null) { instance = new Projector(); } return instance; } public void on() { System.out.println("Projector On"); } public void off() { System.out.println("Projector Off"); } public void focus() { System.out.println("Popcorn is focus"); } //放大 public void zoom(int size) { this.size=size; System.out.println("Popcorn zoom to"+size); } }
Screen.java
package com.bijian.study.facade.hometheater; /** * 屏幕类 * @author bijian * */ public class Screen { private static Screen instance = null; private Screen() { } public static Screen getInstance() { if (instance == null) { instance = new Screen(); } return instance; } //收起来 public void up() { System.out.println("Screen up"); } //放下来 public void down() { System.out.println("Screen down"); } }
Stereo.java
package com.bijian.study.facade.hometheater; /** * 音响类 * @author bijian * */ public class Stereo { private static Stereo instance = null; private int volume = 5; private Stereo() { } public static Stereo getInstance() { if (instance == null) { instance = new Stereo(); } return instance; } public void on() { System.out.println("Stereo On"); } public void off() { System.out.println("Stereo Off"); } //设置音量 public void setVolume(int vol) { volume = vol; System.out.println("the volume of Stereo is set to " + volume); } //加音量 public void addVolume() { if (volume < 11) { volume++; setVolume(volume); } } //减音量 public void subVolume() { if (volume > 0) { volume--; setVolume(volume); } } }
TheaterLights.java
package com.bijian.study.facade.hometheater; /** * 灯光类 * @author bijian */ public class TheaterLights { private static TheaterLights instance = null; private TheaterLights() { } public static TheaterLights getInstance() { if (instance == null) { instance = new TheaterLights(); } return instance; } public void on() { System.out.println("TheaterLights On"); } public void off() { System.out.println("TheaterLights Off"); } //调暗 public void dim(int d) { System.out.println("TheaterLights dim to " + d + "%"); } //调亮 public void bright() { dim(100); System.out.println("TheaterLights bright"); } }
HomeTheaterFacade.java
package com.bijian.study.facade.hometheater; /** * 家庭影院外观模式对象 * @author bijian * */ public class HomeTheaterFacade { private TheaterLights mTheaterLights; private Popcorn mPopcorn; private Stereo mStereo; private Projector mProjector; private Screen mScreen; private DVDPlayer mDVDPlayer; public HomeTheaterFacade() { mTheaterLights = TheaterLights.getInstance(); mPopcorn = Popcorn.getInstance(); mStereo = Stereo.getInstance(); mProjector = Projector.getInstance(); mScreen = Screen.getInstance(); mDVDPlayer = DVDPlayer.getInstance(); } public void ready() { mPopcorn.on(); mPopcorn.pop(); mScreen.down(); mProjector.on(); mStereo.on(); mDVDPlayer.on(); mDVDPlayer.setdvd(); mTheaterLights.dim(10); } public void end() { mPopcorn.off(); mTheaterLights.bright(); mScreen.up(); mProjector.off(); mStereo.off(); mDVDPlayer.setdvd(); mDVDPlayer.off(); } public void play() { mDVDPlayer.play(); } public void pause() { mDVDPlayer.pause(); } }
MainTest.java
package com.bijian.study.facade; import com.bijian.study.facade.hometheater.HomeTheaterFacade; public class MainTest { public static void main(String[] args) { HomeTheaterFacade mHomeTheaterFacade = new HomeTheaterFacade(); mHomeTheaterFacade.ready(); mHomeTheaterFacade.play(); //mHomeTheaterFacade.end(); } }
运行结果:
Popcorn On Popcorn is popping Screen down Projector On Stereo On DVDPlayer On DVDPlayer is setting dvd TheaterLights dim to 10% DVDPlayer is playing
4.外观模式与命令模式
a.命令模式如何设计这个项目
宏命令里面是一个命令的数组,我们可以通过加载命令数组的方式按命令执行。当然,把每个命令变成一个命令对象,再将其放到宏命令里面,然后把宏命令放到我们的外观模式类上,也可以实现这样的功能。
b.外观模式和命令模式各自侧重点
外观模式侧重点是针以系统建一个高层接口,对外暴露几个重要功能,对调用方来说不需要知道里面的细节,是系统对外接口的简化;是一个子系统里面对外暴露的接口进行简化。
命令模式侧重点是把命令包装成对象,本身系统的接口是不变的,至于向外面去暴露出来,它其实是另外一种组合,是组合去解决问题的。侧重点是封装,把命令封装成对象,以后实现解耦,控制器和下面设备的解耦。
外观模式和适配器模式有些类似的地方,适配器一般来说把一个对象或类的接口转化成另一种形式,就像电源插座的转换;而外观模式则是一个系统对外功能或者提供对外接口的简化。
二.最少知识原则
1.最少知识原则的意义
最少知识原则:尽量减少对象之间的交互,只留几个“密友”。
项目设计中就是不要让太多的类耦合在一起。
2.如何遵循最少知识原则
对象的方法调用范围:该对象本身、作为参数传进来的对象、此方法创建和实例化的对象、对象的组件。
一个方法的返回值也是一个对象,作为返回值的对象,在使用时不在这个范围内。所以返回值对象的使用就是违背这个最少知识原则的。
实例:Car这个类里面有一个Engine对象,组件对象实例化后可以直接调用;start方法传进来一个对象Key也可以使用调用;类里面实例化的对象door可以直接调用。当然,如果Key的一个方法返回的是另外一个对象,那就不能调返回的这个对象的方法。
3.外观模式和最少知识原则
外观模式的外观层对外暴露几个接口,把相互交互的对象集缩小了,这就是外观模式应用最少知识原则的实例。