一.外观模式原理
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.外观模式和最少知识原则
外观模式的外观层对外暴露几个接口,把相互交互的对象集缩小了,这就是外观模式应用最少知识原则的实例。