一.什么是外观模式?

简单的说,外观模式是用来简化接口的。

通常,我们觉得一个子系统不好用,可能是因为它提供的外部接口太接近低层组件,让我们用起来感到很麻烦。

因为我们不需要知道内部细节,我们只想要一个“一键完成”功能,调用子系统的某个方法,它可能替我们完成了图片预处理,而不是靠我们自己来调用灰度化方法、图像增强算法、噪声处理方法等等来一步步实现预处理。

如果子系统提供的接口太接近低层组件,不仅不易用,而且破坏了子系统的封装(想调用子系统就必须了解其各个低层组件,我们被迫知道了太多不应该知道的细节。。)

二.举个例子

假设有一个封装好的老式洗衣机,它提供了这些对外接口:

package FacadePattern;

/**
* @author ayqy
* 定义洗衣机接口
*/
public interface Washer {
/*
* 公共部分
* */
//连接电源
public abstract boolean connectToPower(); /*
* 洗涤部分
* */
//打开左侧的洗涤舱
public abstract void openLeftSide();
//打开注水口
public abstract void openWaterHole();
//开始注水
public abstract void startWaterInjection();
//停止注水
public abstract void stopWaterInjection();
//开始旋转左侧洗涤舱
public abstract void startWashing();
//停止旋转左侧洗涤舱
public abstract void stopWashing(); /*
* 脱水部分
* */
//打开右侧的脱水舱
public abstract void openRightSide();
//开始旋转右侧脱水舱
public abstract void startDewatering();
//停止旋转右侧脱水舱
public abstract void stopDewatering(); /*
* 排水部分省略。。
* */
}

没办法,它实在太老了,不能满足我们的现代生活,但我们又买不起新的自动化洗衣机,所以我们需要把它变成一个半自动的洗衣机,用节省下来的时间去写代码。。

先看看我们是如何用老式洗衣机来洗衣服的:

package FacadePattern;

/**
* @author ayqy
* 使用老式洗衣机来洗衣服
*/
public class Washing implements Washer{ public static void main(String[] args) {
//创建洗衣机对象
Washer washer = new Washing();
//连接电源
if(washer.connectToPower()){
//打开洗涤舱
washer.openLeftSide();
/*装入脏衣服过程省略*/
//打开注水口
washer.openWaterHole();
//开始注水
washer.startWaterInjection();
/*等待5分钟*/
//停止注水
washer.stopWaterInjection();
/*添加洗涤剂过程省略*/
//开始洗涤
washer.startWashing();
/*15分钟后停止*/
washer.stopWashing(); /*
* 脱水部分省略
* */
}
} /*
* 忽略下面自动生成的这些东西。。
* */
@Override
public boolean connectToPower() {
// TODO Auto-generated method stub
return false;
} @Override
public void openLeftSide() {
// TODO Auto-generated method stub } @Override
public void openWaterHole() {
// TODO Auto-generated method stub } @Override
public void startWaterInjection() {
// TODO Auto-generated method stub } @Override
public void stopWaterInjection() {
// TODO Auto-generated method stub } @Override
public void startWashing() {
// TODO Auto-generated method stub } @Override
public void stopWashing() {
// TODO Auto-generated method stub } @Override
public void openRightSide() {
// TODO Auto-generated method stub } @Override
public void startDewatering() {
// TODO Auto-generated method stub } @Override
public void stopDewatering() {
// TODO Auto-generated method stub } }

仅仅演示了一个洗衣服的过程,我们就调用了那么多操作,而且我们必须知道这台洗衣机的内部细节,不然根本无法使用它。。

洗衣服可能需要60分钟(注水 + 洗涤 + 脱水 + 排水),在这期间我们几乎什么事情也做不了,只能蹲在洗衣机旁边不停的操作机器

-------

我想,我们可能需要一个遥控器,上面有2个按钮:

  • 洗涤
  • 脱水

然后我们洗衣服的过程会变成这样:

  1. 摁洗涤按钮,自动连接电源,自动打开洗涤舱,自动注水5分钟,自动开始洗涤15分钟
  2. 摁脱水按钮,自动打开脱水舱,自动脱水10分钟,自动排水,自动断开电源

这简直太棒了,我们可以在吃午餐前摁一下洗涤按钮,吃完之后去把衣服拿到右侧,再摁一下脱水按钮,然后去上班,下午回来之后把衣服晾起来就好了

(当然,手动把衣服从左侧拿到右侧的过程是避免不了的,毕竟它太老了,想变成全自动洗衣机是不可能的。。)

来看看我们自己做的遥控器:

package FacadePattern;

/**
* @author ayqy
* 遥控器(也就是所谓的外观)
*/
public class WasherFacade {
private Washer washer; public WasherFacade(Washer washer){
this.washer = washer;
} /**
* 自动洗涤
*/
public void washing(){
//连接电源
if(washer.connectToPower()){
//打开洗涤舱
washer.openLeftSide();
/*装入脏衣服过程省略*/
//打开注水口
washer.openWaterHole();
//开始注水
washer.startWaterInjection();
/*等待5分钟*/
//停止注水
washer.stopWaterInjection();
/*添加洗涤剂过程省略*/
//开始洗涤
washer.startWashing();
/*15分钟后停止*/
washer.stopWashing();
}
} /**
* 自动脱水
*/
public void dewashing(){
/*判断是否已连接电源过程省略*/
//打开右侧的脱水舱
washer.openRightSide();
//开始旋转右侧脱水舱
washer.startDewatering();
//停止旋转右侧脱水舱
washer.stopDewatering(); /*
* 排水过程省略
* 切断电源过程省略
* */
}
}

有了遥控器之后,我们是这样洗衣服的:

package FacadePattern;

/**
* @author ayqy
* 测试应用了外观模式的半自动洗衣机(利用遥控器)
*/
public class Test implements Washer{ public static void main(String[] args) {
//创建老式洗衣机
Washer washer = new Test();
//创建外观(遥控器)
WasherFacade facade = new WasherFacade(washer);
//按下洗涤按钮开始洗衣服
facade.washing();
/*把衣服拿到另一侧*/
//按下脱水按钮开始脱水
facade.dewashing();
} /*
* 忽略下面这些自动生成的东西。。
* */
@Override
public boolean connectToPower() {
// TODO Auto-generated method stub
return false;
} @Override
public void openLeftSide() {
// TODO Auto-generated method stub } @Override
public void openWaterHole() {
// TODO Auto-generated method stub } @Override
public void startWaterInjection() {
// TODO Auto-generated method stub } @Override
public void stopWaterInjection() {
// TODO Auto-generated method stub } @Override
public void startWashing() {
// TODO Auto-generated method stub } @Override
public void stopWashing() {
// TODO Auto-generated method stub } @Override
public void openRightSide() {
// TODO Auto-generated method stub } @Override
public void startDewatering() {
// TODO Auto-generated method stub } @Override
public void stopDewatering() {
// TODO Auto-generated method stub } }

简直轻松惬意,不过仔细一看,不就是定义了一个方法来封装方法调用嘛,有什么了不起的?与在我们的新项目代码中建立定义两个方法负责洗涤和脱水有什么区别吗?

当然有,不要着急

三.外观模式的优点

1.低耦合

先看看我们的命名方式,遥控器叫做WasherFacade,如果要划分模块,它应该与Washer放在一起吧

没错,通过定义Facade,我们成功解耦了Washer与我们的代码,意味着一旦Washer发生变更,我们直接修改Facade就好了,而不是在我们冗长的项目代码里寻找某两个方法

2.保护了子系统的封装

我们并没有打开封装好的Washer去修改,而是添加了一些代码来简化Washer的接口,以前调用者对Washer的内部很了解,但现在它对Washer几乎一无所知(除构造方法外)

3.适用于含有多个不同对象的子系统

例子中的Washer只是一个单一对象,好像应该由Washer本身提供这样的简单接口

但如果要实现日常起居的半自动化,我们会面对多个对象,比如门,窗,窗帘,电视,微波炉,洗衣机,电脑等等

我们希望一键准备早餐(自动开灯,自动开启微波炉加热),一键午睡(自动关门,自动拉上窗帘,自动熄灭灯光)等等功能,外观模式同样适用:

我们只需要让外观多持有几个具体对象就好了

4.有效地简化了子系统的接口

之前洗衣服需要蹲在洗衣机旁不停的操作,现在我们可以“一键完成”了,这才是我们想要的简单易用的接口

5.满足“最少知识原则”

我们做到了“只和朋友交谈”,我们的新系统只认识Facade,只和它交谈,而不是跑去和子系统中的一大堆低层组件交谈

四.总结

外观模式,用来为复杂的子系统提供简单易用的高层接口。

当你纠结于很多低层组件得不到解脱的时候,不妨去做一个遥控器,我想,你可能确实需要它。。

设计模式之外观模式(Facade Pattern)的更多相关文章

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

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

  2. 二十四种设计模式:外观模式(Facade Pattern)

    外观模式(Facade Pattern) 介绍为子系统中的一组接口提供一个一致的界面,Facade模式定义了一个高层接口,这个接口使得这一子系统更加容易使用.示例有一个Message实体类,某对象对它 ...

  3. python : 设计模式之外观模式(Facade Pattern)

    #为啥要用外观模式举例说明 这个例子很形象,直接从人家博客上贴过来的,参考链接在下面 不知道大家有没有比较过自己泡茶和去茶馆喝茶的区别,如果是自己泡茶需要自行准备茶叶.茶具和开水,如图1(A)所示,而 ...

  4. 【UE4 设计模式】外观模式 Facade Pattern

    概述 描述 外部与一个子系统的通信必须通过一个统一的外观对象进行,为子系统中的一组接口提供一个一致的界面,外观模式定义了一个高层接口,这个接口使得这一子系统更加容易使用.外观模式又称为门面模式,它是一 ...

  5. 设计模式系列之外观模式(Facade Pattern)——提供统一的入口

    说明:设计模式系列文章是读刘伟所著<设计模式的艺术之道(软件开发人员内功修炼之道)>一书的阅读笔记.个人感觉这本书讲的不错,有兴趣推荐读一读.详细内容也可以看看此书作者的博客https:/ ...

  6. 使用C# (.NET Core) 实现适配器模式 (Adapter Pattern) 和外观模式 (Facade Pattern)

    本文的概念内容来自深入浅出设计模式一书 现实世界中的适配器(模式) 我带着一个国标插头的笔记本电脑, 来到欧洲, 想插入到欧洲标准的墙壁插座里面, 就需要用中间这个电源适配器. 面向对象的适配器 你有 ...

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

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

  8. 设计模式(八): 从“小弟”中来类比"外观模式"(Facade Pattern)

    在此先容我拿“小弟”这个词来扯一下淡.什么是小弟呢,所谓小弟就是可以帮你做一些琐碎的事情,在此我们就拿“小弟”来类比“外观模式”.在上面一篇博文我们完整的介绍了“适配器模式”,接下来我们将要在这篇博客 ...

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

    一.概述 在系统设计中,某一个系统可能非常庞大,用户要使用该系统就不得不掌握大量的接口,造成使用的不便.这时可以考虑将该系统细分成一系列子系统并使子系统间的耦合降到最低,利用外观模式提供一个外观对象, ...

  10. 外观模式Facade pattern

    http://www.runoob.com/design-pattern/facade-pattern.html 外观模式 外观模式(Facade Pattern)隐藏系统的复杂性,并向客户端提供了一 ...

随机推荐

  1. JS中如何处理多个ajax并发请求?

    js中的多并发处理. 通常 为了减少页面加载时间,先把核心内容显示处理,页面加载完成后再发送ajax请求获取其他数据 这时就可能产生多个ajax请求,为了用户体验,最好是发送并行请求,这就产生了并发问 ...

  2. tf.FIFOQueue()

    Tensorflow–tf.FIFOQueue详解描述tf.FIFOQueue根据先进先出(FIFO)的原则创建一个队列.队列是Tensorflow的一种数据结构,每个队列的元素都是包含一个或多个张量 ...

  3. goim源码分析与二次开发-comet分析一

    因为要完成一个聊天的项目,所以借鉴了goim,第一篇分析打算半原版,先摘抄http://www.jianshu.com/p/8bd96a9a473d他的一些理解,写这些还是为了让自己更好的理解这个项目 ...

  4. vortex

    vortex - Bing dictionary US['vɔr.teks]UK['vɔː(r)teks] n.旋涡:涡旋:低涡:感情(或局势)的旋涡 网络漩涡:涡流:旋风 变形Plural Form ...

  5. HttpClient(一)

    package com.cmy.httpClient; import org.apache.commons.httpclient.HttpClient; import org.apache.commo ...

  6. 操作符重载operator

    发现一篇好文: 转载: http://www.cnblogs.com/xiehongfeng100/p/4040858.html #include <iostream>#include & ...

  7. The valid characters are defined in RFC 7230 and RFC 3986

    网上大都说什么发送格式与协议定义的不兼容,改tomcat版本或改编码之类的. 本人测试的时候换了个浏览器,不用IE就好了 如果坚持用ie,也有解决方式 @参考文章 成功的方法 在请求地址var url ...

  8. php中session入memcached

    1.使用memcache扩展,提供的session处理器(session.save_handler) memcahe即可. 通过存储位置配置项(session.save_path),设置使用的memc ...

  9. 如何在C#中自定义自己的异常

    在C#中所有的异常类型都继承自System.Exception,也就是说,System.Exception是所有异常类的基类. 总起来说,其派生类分为两种:1. SystemException类: 所 ...

  10. 【转】MEF程序设计指南五:迟延(Lazy)加载导出部件(Export Part)与元数据(Metadata)

    MEF中使用导出与导入,实质上就是对一个对象的实例化的过程,通过MEF的特性降低了对象的直接依赖,从而让系统的设计达到一种高灵活.高扩展性的效果.在具体的设计开发中,存在着某些对象是不需要在系统运行或 ...