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

我们已经知道适配器模式是如何将一个类的接口转换成另一个符合客户期望的接口的。现在我们要看一个改变接口的新模式,但是它改变接口的原因是为了简化接口。这个模式被巧妙地命名为外观模式,之所以这么称呼,是因为它将一个或数个类的复杂的一切都隐藏在背后,只显露出一个干净美好的外观。

甜蜜的家庭影院

在我们进入外观模式的细节之前,让我们看一个风行全美的热潮:建立自己的家庭影院。

通过一番研究比较,你组装了一套杀手级的系统,内含DVD播放器、投影机、自动屏幕、环绕立体声,甚至还有爆米花机。

你花了好几个星期布线、挂上投影机、连接所有的装置并进行微调。现在,你准备开始享受一部电影……

挑选一部DVD影片,放松,准备开始感受电影的魔幻魅力。哎呀!忘了一件事:想看电影,必须先执行一些任务:

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

    让我们将这些任务写成类和方法的调用:
// 打开爆米花机,开始爆米花
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);

但还不只这样:

看完电影后,你还要把一切都关掉,怎么办?难道要反向地把这一切动作再进行一次?

如果要听CD或者广播,难道也会这么麻烦?

如果你决定要升级你的系统,可能还必须重新学习一套稍微不同的操作过程。

怎么办?使用你的家庭影院竟变得如此复杂!让我们看看外观模式如何解决这团混乱,好让你能轻易地享受电影。

构造家庭影院外观

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

现在是为家庭影院系统创建一个外观的时候了,于是我们了创建一个名为HomeTheaterFacade的新类,它对外暴露出几个简单的方法,例如watchMovie()。

这个外观类将家庭影院的诸多组件视为一个系统,通过调用这个子系统,来实现watchMovie()方法。

现在,你的客户代码可以调用此家庭影院外观所提供的方法,而不必再调用这个子系统的方法。所以,想要看电影,我们只要调用一个方法(也就是watchMovie())就可以了。灯光、DVD播放器、投影机、功放、屏幕、爆米花,一口气全部搞定。

外观只是提供你更直接的操作,并未将原来的子系统阻隔起来。如果你需要子系统类的更高层功能,还是可以使用原来的子系统。

让我们逐步构造家庭影院外观:第一步是使用组合让外观能够访问子系统中所有的组件。

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

现在该是时候将子系统的组件整合成一个统一的接口了。让我们实现watchMovie()和endMovie()方法。

public void watchMovie(String movie){
// watchMovie()将我们之前手动进行的每项任务依次处理。
// 请注意,每项任务都是委托子系统中相应的组件处理的。
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.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();
}

现在,让我们用轻松的方式去观赏电影:

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

定义外观模式

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

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

现在我们来看一个新的OO原则:

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

这到底是什么意思?这是说,当你正在设计一个系统,不管是任何对象,你都要注意它所交互的类有哪些,并注意它和这些类是如何交互的。

这个原则希望我们在设计中,不要让太多的类耦合在一起,免得修改系统中一部分,会影响到其他部分。如果许多类之间相互依赖,那么这个系统会变成一个易碎的系统,它需要花许多成本维护,也会因为太复杂而不容易被其他人了解。

究竟要怎样才能避免这样呢?这个原则提供了一些方针:就任何对象而言,在该对象的方法内,我们只应该调用属于以下范围的方法:

  1. 该对象本身;
  2. 被当做方法的参数而传递进来的对象;
  3. 此方法所创建或实例化的任何对象;
  4. 对象的任何组件。

    这听起来有点严厉,不是吗?如果调用从另一个调用中返回的对象的方法,会有什么害处呢?如果我们这样做,相当于向另一个对象的子部分发请求(而增加我们直接认识的对象数目)。在这种情况下,原则要我们改为要求该对象为我们做出请求,这么一来,我们就不需要认识该对象的组件了(让我们的朋友圈子维持在最小的状态)。比方说:
// 这里,我们从气象站取得了温度计对象,然后再从温度计对象取得温度
public float getTemp(){
Thermometer thermometer = station.getThermometer();
return thermometer.getTemperature();
} // 在应用最少知识原则时,我们在气象站中加进一个方法,用来向温度计请求温度。
// 这可以减少我们所依赖的类的数目
public float getTemp(){
return station.getTemperature();
}

《Head first设计模式》之外观模式的更多相关文章

  1. 每天一个设计模式-2 外观模式(Facade)

    每天一个设计模式-2  外观模式(Facade) 1.生活中的示例 客户想要购买一台电脑,一般有两种方法: 1.自己DIY,客户需要知道组成电脑的所有电子器件,并且需要熟悉那些配件,对客户要求较高. ...

  2. C#设计模式(11)——外观模式(Facade Pattern)

    一.引言 在软件开发过程中,客户端程序经常会与复杂系统的内部子系统进行耦合,从而导致客户端程序随着子系统的变化而变化,然而为了将复杂系统的内部子系统与客户端之间的依赖解耦,从而就有了外观模式,也称作 ...

  3. 乐在其中设计模式(C#) - 外观模式(Facade Pattern)

    原文:乐在其中设计模式(C#) - 外观模式(Facade Pattern) [索引页][源码下载] 乐在其中设计模式(C#) - 外观模式(Facade Pattern) 作者:webabcd 介绍 ...

  4. 设计模式之 外观模式详解(Service第三者插足,让action与dao分手)

    作者:zuoxiaolong8810(左潇龙),转载请注明出处,特别说明:本博文来自博主原博客,为保证新博客中博文的完整性,特复制到此留存,如需转载请注明新博客地址即可. 各位好,LZ今天给各位分享一 ...

  5. 8.4 GOF设计模式三: 外观模式 Facade

    GOF设计模式三: 外观模式 Facade  “现有系统”功能强大.复杂,开发“新系统”需要用到其中一部分,但又要增加一部 分新功能,该怎么办?4.1 Facade Pattern: Key Fea ...

  6. 北风设计模式课程---外观模式(Facade)总结

    北风设计模式课程---外观模式(Facade)总结 一.总结 一句话总结: 不仅要通过视频学,还要看别的博客里面的介绍,搜讲解,搜作用,搜实例 设计模式都是对生活的抽象,比如用户获得装备,我可以先装备 ...

  7. js设计模式——2.外观模式

    js设计模式——2.外观模式

  8. python设计模式之外观模式

    python设计模式之外观模式 系统会随着演化变得非常复杂,最终形成大量的(并且有时是令人迷惑的)类和交互,这种情况并不少见.许多情况下,我们并不想把这种复杂性暴露给客户端.外观设计模式有助于隐藏系统 ...

  9. java设计模式之外观模式(门面模式)

    针对外观模式,在项目开发和实际运用中十分频繁,但是其极易理解,下面就简要介绍一下. 一.概念介绍 外观模式(Facade),他隐藏了系统的复杂性,并向客户端提供了一个可以访问系统的接口.这种类型的设计 ...

  10. 【GOF23设计模式】外观模式

    来源:http://www.bjsxt.com/ 一.[GOF23设计模式]_外观模式.公司注册流程.迪米特法则 package com.test.facade; public interface 工 ...

随机推荐

  1. 原生js面向对象编程-选项卡(点击)

    <!DOCTYPE html> <html> <head lang="en"> <meta charset="UTF-8&quo ...

  2. Oozie任务调度框架详解及使用简介(一)

    摘要:个人最近一段时间一直在使用oozie,从刚开始的各种别扭到现在越来越觉得有意思的情况下,想整理一下关于oozie的认知,整理出来一个oozie系列,本来市面上关于oozie的资料就比较少,希望写 ...

  3. C#调用7z实现文件的压缩与解压

    1.关于7z 首先在这里先介绍一下7z压缩软件,7z是一种主流的 压缩格式,它拥有极高的压缩比.在计算机科学中,7z是一种可以使用多种压缩算法进行数据压缩的档案格式.主要有以下特点: 来源且模块化的组 ...

  4. Scala实践3

    一.函数式对象 1.1  rational类的规格和创建 Rational类来源于有理数(rational number),来表示n(分子)/d(分母)的数字,同时对有理数的运算(加减乘除)建模,还具 ...

  5. 机器学习-特征工程-Feature generation 和 Feature selection

    概述:上节咱们说了特征工程是机器学习的一个核心内容.然后咱们已经学习了特征工程中的基础内容,分别是missing value handling和categorical data encoding的一些 ...

  6. 关于爬虫的日常复习(14)—— 爬虫beautifulsoup的初级高级的基本用法

  7. Codeforces Round #615 (Div. 3)

    A. Collecting Coins 题目链接:https://codeforces.com/contest/1294/problem/A 题意: 你有三个姐妹她们分别有 a , b , c枚硬币, ...

  8. .net Core Autofac稍微高级一点的方法

    前情摘要 前段时间写了autofac的注入但是每次都需要去修改startup这应该不是大家想要的. 至少不是我想要的. 网上有朋友说可以创建一个基础类来时间. 好了吹牛时间结束我们开始干点正事. 创建 ...

  9. Halo-个人独立博客系统

    项目地址:https://github.com/halo-dev/halo 安装指导:https://halo.run/guide/   简介: Halo 是一款现代化的个人独立博客系统,给习惯写博客 ...

  10. JAVA WebSocket 使用时需要注意的地方

    最近在做一个项目,需要用WebSocket与另外一个平台建立通讯,来获取项目业务需要的实时数据,因此项目一启动,后台就要与另外一个平台建立WebSocket连接并且要保证他们的之间有且只有一条持续畅通 ...