设计模式之外观模式(Facade Pattern)
一.什么是外观模式?
简单的说,外观模式是用来简化接口的。
通常,我们觉得一个子系统不好用,可能是因为它提供的外部接口太接近低层组件,让我们用起来感到很麻烦。
因为我们不需要知道内部细节,我们只想要一个“一键完成”功能,调用子系统的某个方法,它可能替我们完成了图片预处理,而不是靠我们自己来调用灰度化方法、图像增强算法、噪声处理方法等等来一步步实现预处理。
如果子系统提供的接口太接近低层组件,不仅不易用,而且破坏了子系统的封装(想调用子系统就必须了解其各个低层组件,我们被迫知道了太多不应该知道的细节。。)
二.举个例子
假设有一个封装好的老式洗衣机,它提供了这些对外接口:
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个按钮:
- 洗涤
- 脱水
然后我们洗衣服的过程会变成这样:
- 摁洗涤按钮,自动连接电源,自动打开洗涤舱,自动注水5分钟,自动开始洗涤15分钟
- 摁脱水按钮,自动打开脱水舱,自动脱水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)的更多相关文章
- 乐在其中设计模式(C#) - 外观模式(Facade Pattern)
原文:乐在其中设计模式(C#) - 外观模式(Facade Pattern) [索引页][源码下载] 乐在其中设计模式(C#) - 外观模式(Facade Pattern) 作者:webabcd 介绍 ...
- 二十四种设计模式:外观模式(Facade Pattern)
外观模式(Facade Pattern) 介绍为子系统中的一组接口提供一个一致的界面,Facade模式定义了一个高层接口,这个接口使得这一子系统更加容易使用.示例有一个Message实体类,某对象对它 ...
- python : 设计模式之外观模式(Facade Pattern)
#为啥要用外观模式举例说明 这个例子很形象,直接从人家博客上贴过来的,参考链接在下面 不知道大家有没有比较过自己泡茶和去茶馆喝茶的区别,如果是自己泡茶需要自行准备茶叶.茶具和开水,如图1(A)所示,而 ...
- 【UE4 设计模式】外观模式 Facade Pattern
概述 描述 外部与一个子系统的通信必须通过一个统一的外观对象进行,为子系统中的一组接口提供一个一致的界面,外观模式定义了一个高层接口,这个接口使得这一子系统更加容易使用.外观模式又称为门面模式,它是一 ...
- 设计模式系列之外观模式(Facade Pattern)——提供统一的入口
说明:设计模式系列文章是读刘伟所著<设计模式的艺术之道(软件开发人员内功修炼之道)>一书的阅读笔记.个人感觉这本书讲的不错,有兴趣推荐读一读.详细内容也可以看看此书作者的博客https:/ ...
- 使用C# (.NET Core) 实现适配器模式 (Adapter Pattern) 和外观模式 (Facade Pattern)
本文的概念内容来自深入浅出设计模式一书 现实世界中的适配器(模式) 我带着一个国标插头的笔记本电脑, 来到欧洲, 想插入到欧洲标准的墙壁插座里面, 就需要用中间这个电源适配器. 面向对象的适配器 你有 ...
- 8.4 GOF设计模式三: 外观模式 Facade
GOF设计模式三: 外观模式 Facade “现有系统”功能强大.复杂,开发“新系统”需要用到其中一部分,但又要增加一部 分新功能,该怎么办?4.1 Facade Pattern: Key Fea ...
- 设计模式(八): 从“小弟”中来类比"外观模式"(Facade Pattern)
在此先容我拿“小弟”这个词来扯一下淡.什么是小弟呢,所谓小弟就是可以帮你做一些琐碎的事情,在此我们就拿“小弟”来类比“外观模式”.在上面一篇博文我们完整的介绍了“适配器模式”,接下来我们将要在这篇博客 ...
- C#设计模式——外观模式(Facade Pattern)
一.概述 在系统设计中,某一个系统可能非常庞大,用户要使用该系统就不得不掌握大量的接口,造成使用的不便.这时可以考虑将该系统细分成一系列子系统并使子系统间的耦合降到最低,利用外观模式提供一个外观对象, ...
- 外观模式Facade pattern
http://www.runoob.com/design-pattern/facade-pattern.html 外观模式 外观模式(Facade Pattern)隐藏系统的复杂性,并向客户端提供了一 ...
随机推荐
- Codeforces Beta Round #9 (Div. 2 Only)
Codeforces Beta Round #9 (Div. 2 Only) http://codeforces.com/contest/9 A gcd水题 #include<bits/stdc ...
- Connections in Galaxy War(逆向并查集)
Connections in Galaxy War http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemId=3563 Time Limit ...
- VCP考试系统
题目的格式如下,题目和题目之间用“==”隔开,每个题目的“题干”,“选项”,“答案”用“*”号隔开 An administrator wants to provide users restrict ...
- Newtonsoft.Json自动升级版本号,导致dll冲突
不知道怎么回事,vs偶尔会自动升级Newtonsoft.Json.dll的版本号,但是又不升级dll,仅仅是版本号变了,实际引用的dll还是原来的. 我用的是6.0.0的,然后版本号升级成了7.0.0 ...
- ajax.beginform控制器中实体为null的问题
控制器: 函数声明:public JsonResult ApplyFun(Test test) 原因:在视图中有一个表单的name属性为test,因为冲突所导致.
- 从输入url到显示网页发生了什么
原文链接:https://juejin.im/post/5bf23afa6fb9a049be5d1494 在浏览器中输入url到显示网页主要包含两个部分: 网络通信和页面渲染 互联网内各网络设备间的通 ...
- loadrunner12-运行报错原因及解决办法整理集合
1.错误:已超过该load generator的CPU使用率80%: 答:机器内存过小,更换配置更好的机器来执行测试. 是因为虚机的内存过小,运行Controller需要消耗的CPU过高,超过了80% ...
- 实验 Attacks on TCP/IP Protocols
------- 转载请注明出处,博客园-lasgalen-http://www.cnblogs.com/lasgalen/p/4555648.html ------- 1 实验目的 进行这个实验的目的 ...
- @RequestMapping 介绍
RequestMapping是一个用来处理请求地址映射的注解,可用于类或方法上.用于类上,表示类中的所有响应请求的方法都是以该地址作为父路径. RequestMapping注解有六个属性,下面我们把她 ...
- C语言中以字符串形式输出枚举变量
C语言中以字符串形式输出枚举变量 摘自:https://blog.csdn.net/haifeilang/article/details/41079255 2014年11月13日 15:17:20 h ...