bboyjing's blog

HeadFirst设计模式八【外观模式】

上一节适配器模式最后引出了外观模式,再重申一下外观模式的作用。它是一个改变接口的新模式,但是改变接口的原因是为了简化接口。它将一个或数个类的复杂的一切隐藏在背后,只显露出一个干净美好的外观。

场景描述

假设我们家里建立一套家庭影院,经过一番研究,组装了一套杀手级的系统 。内含DVD播放器、投影机、自动屏幕、环绕立体声,甚至还有爆米花机。花了好几个星期布线、挂上投影机、连接所有的装置并调试。现在,准备开始享受一部电影了,但是得先执行如下任务:

  1. 打开爆米花机
  2. 开始爆米花
  3. 将灯光调暗
  4. 放下屏幕
  5. 打开投影机
  6. 将投影机的输入切换到DVD
  7. 将投影机设置在宽屏模式
  8. 打开功放
  9. 将功放的输入设置为DVD
  10. 将功放设置为环绕立体声
  11. 将功放音量调到中(5)
  12. 打开DVD播放器
  13. 开始播放DVD

要看一场电影真是不容易,如果每次都这样的话,这套设备要吃灰了。更何况还不止这样:

  • 看完电影后,还要把一切都关掉,怎么办?难道要反向地把这一切动作再执行一遍?
  • 如果要听CD或广播,难道也这么麻烦?
  • 如果决定要升级系统,可能还必须重新学习一套稍微不同的操作过程。

下面我们就来看看外观模式是如何解决这团混乱的。

代码示例

本示例涉及到的类会比较多,有爆米花机、灯、屏幕、CD机等。为了简单,我们只抽取其中两个类来演示下。假设现在流程只简化到,灯关掉,然后开启DVD机,按播放按钮,就可以了。

  1. 创建电灯,只有开灯和关灯两个方法。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    public class TheaterLight {
    public void on() {
    System.out.println("TheaterLight on");
    }
    public void off() {
    System.out.println("TheaterLight off");
    }
    }
  2. 创建DVD播放器

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    public class DvdPlayer {
    String movie;
    public void on() {
    System.out.println("DvdPlayer on");
    }
    public void off() {
    System.out.println("DvdPlayer off");
    }
    public void play(String movie) {
    this.movie = movie;
    System.out.println("DvdPlayer playing " + movie);
    }
    public void stop() {
    System.out.println("DvdPlayer stopped");
    }
    }
  3. 创建家庭影院外观

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    public class HomeTheaterFacade {
    private TheaterLight theaterLight;
    private DvdPlayer dvdPlayer;
    public HomeTheaterFacade(TheaterLight theaterLight, DvdPlayer dvdPlayer) {
    this.theaterLight = theaterLight;
    this.dvdPlayer = dvdPlayer;
    }
    public void watchMovie(String movie) {
    System.out.println("Get ready to watch a movie...");
    theaterLight.off();
    dvdPlayer.on();
    dvdPlayer.play(movie);
    }
    public void endMovie() {
    System.out.println("Shutting movie theater down...");
    dvdPlayer.stop();
    dvdPlayer.off();
    theaterLight.on();
    }
    }
  4. 测试

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    public class Test {
    public static void main(String[] args) {
    TheaterLight theaterLight = new TheaterLight();
    DvdPlayer dvdPlayer = new DvdPlayer();
    HomeTheaterFacade homeTheaterFacade = new HomeTheaterFacade(theaterLight, dvdPlayer);
    homeTheaterFacade.watchMovie("Gone With Wind");
    homeTheaterFacade.endMovie();
    }
    }

从代码可以看出,这个模式也很简单,主要是逻辑上简单。其实也就是创建了一个Facade,来组合各个零件的接口,然后提供了一个更简单接口来供别人使用。我们再回顾下适配器模式,通过代码可以体会出其中的区别:适配器模式是转换接口,火鸡当鸭子用;而外观模式是通过组合封装的方式来简化接口,将流程串起来,变成一个一目了然的接口再提供出去。本章节就到这里了。