您的位置:首页 > 其它

《HeadFirst设计模式》读书笔记-第7章-外观模式

2017-04-20 23:44 225 查看

定义

外观模式(facade pattern)提供了一个统一的接口,用来访问子系统中的一群接口。外观定义了一个高层接口,让子系统更加容易使用。



从上面的图可以看出,Facade类对子系统进行了一下封装,客户只需要和Facade类打交道,不需要接触子系统中的各个类,也不需要了解子系统中各个类间的关系。从这个角度来说,客户也就从组件中的子系统中解耦了,不需要依赖于子系统中具体的类了。

外观模式的一个重要的目的就是简化系统,提供给客户一个简单的接口,方便客户使用。

代码实现

例子是为家庭影院构造外观,让观看电影的步骤尽可能地简单。下图给出了类图。



首先看看HomeTheaterFacade这个高层接口,它提供了6个接口分别执行6个动作,每个动作是通过调用子系统中其它的类来实现的。

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;
}

// 开始观看名为“movie”的电影接口
public void watchMovie(String movie) {
System.out.println("Get ready to watch a movie...");
popper.on(); // 打开爆米花机
popper.pop(); // 开始爆米花
lights.dim(10); // 调低灯光亮度为10%
screen.down(); // 放下屏幕
projector.on(); // 打开投影机
projector.wideScreenMode(); // 设置宽屏模式
amp.on(); // 打开功放
amp.setDvd(dvd);
amp.setSurroundSound(); // 设置环绕立体声
amp.setVolume(5); // 设置音量
dvd.on();  // 打开DVD播放器
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播放器
dvd.off();
}

public void listenToCd(String cdTitle) {
System.out.println("Get ready for an audiopile experence...");
lights.on();
amp.on();
amp.setVolume(5);
amp.setCd(cd);
amp.setStereoSound();
cd.on();
cd.play(cdTitle);
}

public void endCd() {
System.out.println("Shutting down CD...");
amp.off();
amp.setCd(cd);
cd.eject();
cd.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();
}
}


因为子系统中类太多了,这里只列出一个,其它的类似。

public class Amplifier {
String description;
Tuner tuner;
DvdPlayer dvd;
CdPlayer cd;

public Amplifier(String description) {
this.description = description;
}

public void on() {
System.out.println(description + " on");
}

public void off() {
System.out.println(description + " off");
}

public void setStereoSound() {
System.out.println(description + " stereo mode on");
}

public void setSurroundSound() {
System.out.println(description + " surround sound on (5 speakers, 1 subwoofer)");
}

public void setVolume(int level) {
System.out.println(description + " setting volume to " + level);
}

public void setTuner(Tuner tuner) {
System.out.println(description + " setting tuner to " + dvd);
this.tuner = tuner;
}

public void setDvd(DvdPlayer dvd) {
System.out.println(description + " setting DVD player to " + dvd);
this.dvd = dvd;
}

public void setCd(CdPlayer cd) {
System.out.println(description + " setting CD player to " + cd);
this.cd = cd;
}

public String toString() {
return description;
}
}


测试驱动代码,也是客户代码:

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);
// 客户开始/停止看电影只要调用高层接口的Api即可
// 不需要和子系统中其它类交互
// 当然客户需要调用子系统中某个类时,也是允许的
homeTheater.watchMovie("Raiders of the Lost Ark");
homeTheater.endMovie();
}
}


本章金句

外观模式不只是简化了子系统的接口,也将客户从组件的子系统中解耦

外观只是对子系统的接口进行了更高层次的抽象,客户还是可以直接调用子系统中的类的,当然一般情况这是不必要的,只要外观接口定义的好

外观模式符合“最少知识原则”

适配器模式和外观模式的差别:

两种模式都是对其它的接口的再次封装。差别在适配器强调对一个或者多个接口的转换,而外观模式则强调简化接口
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息