第九章 外观模式
1.1 引言
在现实世界中,观看电影可能需要如下步骤:
- 打开爆米花机
- 开始爆米花
- 将灯光调暗
- 放下屏幕
- 打开投影仪
- 将投影仪的输入切换到DVD
- 将投影仪设置在宽屏模式
- …
可以看到观看电影需要对诸多子系统进行操作,因此,客户代码与诸多子系统耦合,为减少客户代码与子系统的耦合,引入外观模式。
1.2 外观模式
外观模式提供了一个统一的接口,用来访问子系统中的一群接口。外观定义了一个高层接口,让子系统更容易使用。
外观模式的类图如下图所示。
类图中的Facade是一个统一的接口,即高层接口,实现了客户与子系统之间的耦合。
1.3 使用外观模式——构造家庭电影院外观
定义电影院 HomeTheaterFacade 高层接口:
package headfirst.designpatterns.facade.hometheater;
public class HomeTheaterFacade {
Amplifier amp;
Tuner tuner;
StreamingPlayer player;
CdPlayer cd;
Projector projector;
TheaterLights lights;
Screen screen;
PopcornPopper popper;
public HomeTheaterFacade(Amplifier amp,
Tuner tuner,
StreamingPlayer player,
Projector projector,
Screen screen,
TheaterLights lights,
PopcornPopper popper) {
this.amp = amp;
this.tuner = tuner;
this.player = player;
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.setStreamingPlayer(player);
amp.setSurroundSound();
amp.setVolume(5);
player.on();
player.play(movie);
}
public void endMovie() {
System.out.println("Shutting movie theater down...");
popper.off();
lights.on();
screen.up();
projector.off();
amp.off();
player.stop();
player.off();
}
public void listenToRadio(double frequency) {
System.out.println("Tuning in the airwaves...");
tuner.on();
tuner.setFrequency(frequency);
amp.on();
amp.setVolume(5);
amp.setTuner(tuner);
}
public void endRadio() {
System.out.println("Shutting down the tuner...");
tuner.off();
amp.off();
}
}
客户代码 HomeTheaterTestDrive :
package headfirst.designpatterns.facade.hometheater;
public class HomeTheaterTestDrive {
public static void main(String[] args) {
Amplifier amp = new Amplifier("Amplifier");
Tuner tuner = new Tuner("AM/FM Tuner", amp);
StreamingPlayer player = new StreamingPlayer("Streaming Player", amp);
CdPlayer cd = new CdPlayer("CD Player", amp);
Projector projector = new Projector("Projector", player);
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, player,
projector, screen, lights, popper);
homeTheater.watchMovie("Raiders of the Lost Ark");
homeTheater.endMovie();
}
}
测试结果:
Cricket Game Initialized! Start playing.
Cricket Game Started. Enjoy the game!
Cricket Game Finished!
Football Game Initialized! Start playing.
Football Game Started. Enjoy the game!
Football Game Finished!
在外观模式中,使用了最少知识原则。
1.4 最少知识原则
最少知识原则:不要让太多的类耦合在一起,免得修改系统中一部分,会影响到其他部分,维护成本升高。
在对象的方法内,我们应尽量调用属于以下范围的方法:
- 该对象本身的方法
- 被当作方法的参数而传递进来的对象
- 此方法所创建或实例化的任何对象(方法内实例的对象)
- 对象的任何组件(域对象)
参考
[1] Freeman E. Head First 设计模式[M] 中国电力出版社.
[2] 菜鸟教程.