《Head First Design Patterns》:第7章,外观(Facade)模式

外观模式的定义

场景

观看家庭影院

场景描述

你组装了一套家庭影院,包含DVD播放器、投影机、自动屏幕、环绕立体声,甚至还有爆米花机,如下图:

现在你准备开始享受一部电影,你要做:

  1. 打开爆米花机;
  2. 开始爆米花;
  3. 将灯光调暗;
  4. 放下屏幕;
  5. … …(此处省略N步)

代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
popper.on();
popper.pop();

lights.dim(10);

screen.down();

projector.on();
projector.setInput(dvd);
projector.wideScreenMode();

amp.on();
amp.setDvd(dvd);
amp.setSurroundSound();
amp.setVolume(5);

dvd.on();
dvd.play(movie);

可以看到,播放电影我们就要做很多事情;同样,看完电影,你还要把一切都要关掉,还有很多事情等着你要去做。

方案

使用外观模式,通过实现一个提供了更合理接口的外观类,你可以将一个复杂的子系统变得容易使用。如果你需要原复杂子系统的强大威力,仍然可以使用原来的复杂接口;但如果你需要的是一个方便使用的接口,那么就使用外观类。

为家庭影院系统创建一个外观类HomeTheaterFacade,该类对外暴露出了几个简单的方法:watchMovie()endMovie()listenToRadio()endRadio()。这个外观类将家庭影院的各个组件看作成一个子系统,通过这个子系统来实现外观类中的接口。这样,客户代码就可以调用此外观类所提供的方法,而不必再调用这个子系统中各个组件的方法。所以,想要看电影,只需要调用一个方法watchMovie()就行了。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
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();
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
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();
}

外观模式VS适配器模式