目录

外观模式

Facade Pattern

外观模式(Facade pattern),是软件工程中常用的一种软件设计模式,它为子系统中的一组界面提供一个统一的高层界面,使得子系统更容易使用。

定义

一个改变接口的新模式,但是它改变接口的原因是为了简化接口。这个模式被巧妙地命名为外观模式,之所以这么称呼,是因为它将一个或数个类的复杂的一切都隐藏在背后,只显露出一个干净美好的外观。

想要使用外观模式,我们创建了一个接口简化而统一的类,用来包装子系统中一个或多个复杂的类。外观模式相当直接,很容易理解,这方面和许多其他的模式不太一样。但这并不会降低它的威力:外观模式允许我们让客户和子系统之间避免紧耦合。 外观模式提供了一个统一的接口,用来访问子系统中的一群接口。外观定义了一个高层接口,让子系统更容易使用。

OO原则

最少知识原则:只和你的密友谈话。

结构

  • Facade 这个外观类为子系统中Packages 1、2、3提供一个共同的对外界面(接口)
  • Clients 客户对象通过一个外观界面读写子系统中各界面的数据资源。
  • Packages 客户可以通过外观界面读取的内部库。

实现

在进入外观模式的细节之前,让我们看如何建立自己的家庭影院。通过一番研究比较,你组装了一套杀手级的系统,内含DVD播放器、投影机、自动屏幕、环绕立体声,甚至还有爆米花机。 你花了好几个星期布线、挂上投影机、连接所有的装置并进行微调。现在,你准备开始享受一部电影……

家庭影院观影过程

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
// 打开爆米花机,开始爆米花
popper.on();
popper.pop(); 
// 灯光调到10%的亮度
lights.dim(10); 
// 把屏幕放下来
screen.down(); 
// 打开投影机,并将它设置在宽屏模式
projector.on();
projector.setInput(dvd);
projector.wideScreenMode(); 
// 打开功放,设置为DVD,调整成环绕立体声模式,音量调到5
amp.on();
amp.setDvd(dvd);
amp.setSurroundSound();
amp.setVolume(5); 
// 打开DVD机,“终于”可以看电影了!
dvd.on();
dvd.play(movies);

外观

 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
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,
                             TheaterLights lights,
                             Screen screen,
                             PopcornPopper popper) {
        this.amp = amp;
        this.tuner = tuner;
        this.dvd = dvd;
        this.cd = cd;
        this.projector = projector;
        this.lights = lights;
        this.screen = screen;
        this.popper = popper;
    }
    public void watchMovie(String movie){
    // watchMovie()将我们之前手动进行的每项任务依次处理。
    // 请注意,每项任务都是委托子系统中相应的组件处理的。
    System.out.println("Get ready to watch " + movie);
    popper.on();
    popper.pop();
    lights.dim(10);
    screen.down();
    projector.on();
    projector.wideScreenMode();
    amp.on();
    amp.setDvd(dvd);
    amp.setSurroundSound();
    amp.setVolume(5);
    dvd.on();
    dvd.play(movie);
  } 
  public void endMovie(){
    // endMovie()负责关闭一切。每项任务也是委托子系统中合适的组件处理的。
    System.out.println("Shutting movie theater down");
    popper.off();
    lights.on();
    screen.up();
    projector.off();
    amp.off();
    dvd.stop();
    dvd.eject();
    dvd.off();
  }
}

测试

1
2
3
HomeTheaterFacade homeTheaterFacade = new HomeTheaterFacade(amp, tuner, dvd, cd, projector, lights, screen, popper);
homeTheaterFacade.watchMovie("Pulp Fiction");
homeTheaterFacade.endMovie();

附录