引入
定义:外观模式提供了一个统一的接口,用来访问子系统中的一群接口。外观定义了一个高层接口,让子系统更容易使用。
UML类图
这个模式类图我么可以感受到,外观的意图是提供一个简单的接口,好让一个子系统更容易使用。
1.Facade 角色 对外提供统一的接口,让客户端访问子系统
2.子系统是一个集合或者多个系统,每个子系统都可以被客户端直接调用,或者通过facade调用。
示例
引用head first 的一个例子
我们这里有一套家庭影院系统。我们看看这些组件的组成
我们在看电影之前要做的事情
1.打开爆米花机
2.开始爆米花
3.将灯光调暗
4.放下屏幕
5.打开投影仪
。。。。
打开dvd播放器
开始播放dvd
只想观看一部影片,却做了这么多繁琐的操作。。。。
而且每次看完电影还要把所有都关掉,这简直太不友好了。我们决定使用外观模式解决这个糟糕的问题!
改造
我们需要一个外观,通过外观模式,实现一个提供更合理的接口的外观类,你可以将一个复杂的子系统变得更容易使用。如果你需要复杂子系统的强大威力,还是可以使用原来的复杂接口。但如果你需要的是一个方便使用的接口,那就是使用外观。
现在,我们只需药调用家庭影院外观所提供的方法,不必再调用这个子系统的方法。所以,现在我们看电影,只需药调用watchMovie()就可以了,灯光,dvd播放器,投影仪,公放等,一切全部搞定
外观只是提供你更直接的操作,并未将原来的子系统阻隔起来。如果你需要子系统类的更高层功能,还是可以使用原来的子系统。
外国模式和适配器模式对比:
1.外观不只是简化了接口,也是将客户从组件的子系统中解耦
2.外观和适配器可以包装许多类,但外观的意图是简化接口,而适配器的意图是将接口转化成不同的接口。
示例
这里引用head first上的一个家庭影院的例子(可能不是很恰当,重在说明思想),基于上面模型的例子
子系统类
package com.zpkj.project15;
/**
* 公放类
*/
public class Amplifier {
private Tuner tuner;
private CdPlayer cdPlayer;
private DvdPlayer dvdPlayer;
public Amplifier(Tuner tuner, CdPlayer cdPlayer, DvdPlayer dvdPlayer) {
super();
this.tuner = tuner;
this.cdPlayer = cdPlayer;
this.dvdPlayer = dvdPlayer;
}
public void onDvd(){
System.out.println("开启公放");
}
public void offDvd(){
System.out.println("关闭公放");
}
public void setSurroundSound(){
dvdPlayer.setSurroundAudio();
}
public void dvdPlay(){
dvdPlayer.play();
}
}
package com.zpkj.project15;
/**
* cd播放器
*/
public class CdPlayer {
public void on(){
System.out.println("开启cd");
}
public void off(){
System.out.println("关闭cd");
}
public void stop(){
System.out.println("暂停");
}
public void play(){
System.out.println("开始播放");
}
}
package com.zpkj.project15;
/**
* dvd播放器
*/
public class DvdPlayer {
public void on(){
System.out.println("开启dvd");
}
public void off(){
System.out.println("关闭dvd");
}
public void stop(){
System.out.println("暂停");
}
public void play(){
System.out.println("开始播放");
}
public void setSurroundAudio(){
System.out.println("环绕音");
}
}
package com.zpkj.project15;
/**
* 爆玉米花设配
*/
public class PopcornPopper {
public void on(){
System.out.println("开启爆米花机");
}
public void off(){
System.out.println("关闭爆米花机");
}
public void pop(){
System.out.println("爆爆米花");
}
}
package com.zpkj.project15;
/**
* 投影仪设配
*/
public class Projector {
private DvdPlayer dvdPlayer;
public Projector(DvdPlayer dvdPlayer) {
super();
this.dvdPlayer = dvdPlayer;
}
public void on(){
System.out.println("开启投影");
}
public void off(){
System.out.println("关闭投影");
}
public void tvMode(){
System.out.println("观影模式");
}
public void wideScreenMode(){
System.out.println("宽屏模式");
}
}
package com.zpkj.project15;
/**
* 屏幕
*/
public class Screen {
public void up(){
System.out.println("屏幕上升");
}
public void down(){
System.out.println("屏幕下降");
}
}
package com.zpkj.project15;
/**
* 影院灯光
*/
public class TheaterLight {
public void on(){
System.out.println("开启影院灯光");
}
public void off(){
System.out.println("关闭影院灯光");
}
public void dim(){
System.out.println("观影模式灯光");
}
}
package com.zpkj.project15;
/**
* 调音设配
*/
public class Tuner {
public void on(){
System.out.println("开启调音");
}
public void off(){
System.out.println("关闭调音");
}
public void setAm(){
System.out.println("加大声音");
}
public void setPm(){
System.out.println("减小声音");
}
}
Facade 角色
package com.zpkj.project15;
public class HomeTheaterFacade {
private Amplifier amplifier;
private Tuner tuner;
private DvdPlayer dvdPlayer;
private CdPlayer cdPlayer;
private Projector projector;
private TheaterLight light;
private Screen screen;
private PopcornPopper popcornPopper;
public HomeTheaterFacade(Amplifier amplifier, Tuner tuner,
DvdPlayer dvdPlayer, CdPlayer cdPlayer, Projector projector,
TheaterLight light, Screen screen, PopcornPopper popcornPopper) {
super();
this.amplifier = amplifier;
this.tuner = tuner;
this.dvdPlayer = dvdPlayer;
this.cdPlayer = cdPlayer;
this.projector = projector;
this.light = light;
this.screen = screen;
this.popcornPopper = popcornPopper;
}
public void watchMovie(){
System.out.println("let’s go");
popcornPopper.on();
popcornPopper.pop();
light.on();
light.dim();
screen.down();
projector.on();
projector.wideScreenMode();
amplifier.onDvd();
amplifier.setSurroundSound();
dvdPlayer.on();
dvdPlayer.play();
}
public void endMovie(){
System.out.println("shutting movie theater dowm...");
popcornPopper.off();
light.off();
screen.up();
projector.off();
amplifier.offDvd();
dvdPlayer.stop();
dvdPlayer.off();
}
}
Client角色
package com.zpkj.project15;
public class Client {
public static void main(String[] args) {
Tuner tuner = new Tuner();
CdPlayer cdPlayer = new CdPlayer();
DvdPlayer dvdPlayer = new DvdPlayer();
Amplifier amplifier = new Amplifier(tuner, cdPlayer, dvdPlayer);
Projector projector = new Projector(dvdPlayer);
TheaterLight theaterLight = new TheaterLight();
Screen screen = new Screen();
PopcornPopper popcornPopper = new PopcornPopper();
HomeTheaterFacade homeTheaterFacade = new HomeTheaterFacade(amplifier, tuner, dvdPlayer, cdPlayer, projector, theaterLight, screen, popcornPopper);
homeTheaterFacade.watchMovie();
System.out.println("-----------------");
homeTheaterFacade.endMovie();
}
}
结果
oo原则
1.最少知识原则:只和你的密友谈话
这个原则希望我们在设计中,不要让太多类耦合在一起,免得修改系统中一部分,会影响到其他部分。如果许多类之间相互依赖,那么这个系统就会变成一个易碎的系统,造成维护成本增加。
总结
1.当需要简化并统一一个很大的接口或者一群复杂的接口时,使用外观模式
2.外观将客户从一个复杂的子系统中解耦
3.实现一个外观,需要将子系统 组合进外观中,然后将工作委任给子系统执行。
4.你可以为一个子系统实现一个以上的外观。