外观模式的基本概念

  首先,我们要先了解一下外观模式的基本概念。那到底什么是外观模式?其实就是基于很多模块或者很多子系统提供的一个最高层的接口,控制客户端访问我们的应用程序,减少客户端直接对内部应用程序的调用。也可以说是客户端和应用程序之间的第一道桥梁或者一个简化过的调用模版。我从网上偷了一张图,大家可以看一下:

  如果不使用外观模式的话,我们通常是Client端直接调用具体的模块,这样子系统的具体API就会暴露在客户端,而且调用起来的处理逻辑都要客户端去处理,很明显这违反了开闭原则,程序的扩展性非常的差。如果客户端的逻辑需要改变,则可能客户端的逻辑需要重新编码。如果使用的是外观模式,则可以把这些变动放在外观类中,客户端无需修改,代码的整体上扩展性更强,代码更具有健壮性。

  具体的举两个具体的例子,我们生活中大家都去组装过台式电脑,电脑的零配件包括CPU,显卡,显示器等等这些。我们从市场上买了材料,我们需要自己组装,拿着一堆零件狂装一通,最后装好了,开机使用,发现根本开不了机,结果发现显卡的线差错了。如果从代码的角度来看的话,电脑的零配件相当于我们的模块或者说是子系统,而我们组装电脑的过程相当于客户端,我们进行一通调用,结果发现我们需要调用的逻辑跟我们其他的业务逻辑代码写在一起,结果调用的时候出问题了,也就是我们前面说的电脑无法开机,这个时候我们又是debug调试,打日志观察结果,这样下来,一天过去了,然而今天的工作量基本为零。如果我们把电脑交给装配店去组装,我们直接拿过来用,不仅简洁,而且效率更高,不需要我们具体的去一步一步实现,事半功倍。我们代码中如果能直接调用这一系列的逻辑和API,我们代码会非常的容易维护和调试,下面这个小例子的代码贴上来:

Cpu的接口:

package com.bane.example1.computer;/***
* @ClassName: CpuExecutor
* @Description: TODO(组装电脑的CPU)
* @author 于继伟
* @date 2017-10-21 下午10:49:57
**/
public interface CpuExecutor {void cpu();}

显示器的接口:

package com.bane.example1.computer;/***
* @ClassName: ViewExecutor
* @Description: TODO(组装显示器的接口)
* @author 于继伟
* @date 2017-10-21 下午10:51:09
**/
public interface ViewExecutor {void view();}

Cpu的具体实现:

package com.bane.example1.computer.impl;import com.bane.example1.computer.CpuExecutor;/***
* @ClassName: CpuExecutorImpl
* @Description: TODO(CPU具体实现)
* @author 于继伟
* @date 2017-10-21 下午10:52:16
**/
public class CpuExecutorImpl implements CpuExecutor{@Overridepublic void cpu() {System.out.println("组装CPU");}}

显示器的具体实现:

package com.bane.example1.computer.impl;import com.bane.example1.computer.ViewExecutor;/***
* @ClassName: ViewExecutorImpl
* @Description: TODO(View具体实现)
* @author 于继伟
* @date 2017-10-21 下午10:52:44
**/
public class ViewExecutorImpl implements ViewExecutor{@Overridepublic void view() {System.out.println("组装显示器");}}

组装电脑的外观类:

package com.bane.example1.computer.impl;import com.bane.example1.computer.ViewExecutor;/***
* @ClassName: ViewExecutorImpl
* @Description: TODO(View具体实现)
* @author 于继伟
* @date 2017-10-21 下午10:52:44
**/
public class ViewExecutorImpl implements ViewExecutor{@Overridepublic void view() {System.out.println("组装显示器");}}

主方法测试:

package com.bane.example1;import com.bane.example1.facade.ComputerFacade;/***
* @ClassName: Main
* @Description: TODO(主方法测试类)
* @author 于继伟
* @date 2017-10-21 下午10:47:29
**/
public class Main {public static void main(String[] args) {ComputerFacade computerFacade = new ComputerFacade();computerFacade.computer();}}

控制台输出:

组装CPU
组装显示器

  假如我们现在需要写这样一个工具,就是一键生成从控制层到Dao层的基础代码,减少我们基础代码的开发工作。也就是说我们这个工具有四个模块,一个生成控制层代码的模块,一个生成业务层代码的模块,一个生成Dao层代码的模块,以及我们生成代码的配置模块。按照我们前面所说的,这里非常适合使用外观模式。使用发一个外观类,去控制和管理这一系列的模块来完成我们的生成代码的功能。话不多说,我们直接上代码:

配置模块的代码如下:

package com.bane.example2.config;/***
* @ClassName: ConfigModel
* @Description: TODO(生成代码的配置基类)
* @author 于继伟
* @date 2017-10-22 上午9:57:06
**/
public class ConfigModel {/*** 是否需要生成表现层,默认是true*/private boolean needGenPresentation = true;/*** 是否需要生成逻辑层,默认是true*/private boolean needGenBusiness = true;/*** 是否需要生成Dao,默认是true*/private boolean needGenDao = true;public boolean isNeedGenPresentation() {return needGenPresentation;}public void setNeedGenPresentation(boolean needGenPresentation) {this.needGenPresentation = needGenPresentation;}public boolean isNeedGenBusiness() {return needGenBusiness;}public void setNeedGenBusiness(boolean needGenBusiness) {this.needGenBusiness = needGenBusiness;}public boolean isNeedGenDao() {return needGenDao;}public void setNeedGenDao(boolean needGenDao) {this.needGenDao = needGenDao;}}

package com.bane.example2.config;/***
* @ClassName: ConfigManager
* @Description: TODO(示意配置管理,就是负责读取配置文件,并且把文件的内容设置到配置Model中去,是个单例)
* @author 于继伟
* @date 2017-10-22 上午9:59:54
**/
public class ConfigManager {private static ConfigManager manager = null;private static ConfigModel cm = null;private ConfigManager(){}public static ConfigManager getInstance(){if(manager == null){manager = new ConfigManager();cm = new ConfigModel();//读取配置文件,把值设置到ConfigModel中去
        }return manager;}/*** 获取配置的数据* @return*/public ConfigModel getConfigData(){return cm;}
}

具体的生成代码的模块:

package com.bane.example2.executor;/***
* @ClassName: BaseExecutor
* @Description: TODO(模块生成的基类)
* @author 于继伟
* @date 2017-10-22 上午10:55:15
**/
public abstract class BaseExecutor {public abstract void generate();}

package com.bane.example2.executor;import com.bane.example2.config.ConfigManager;
import com.bane.example2.config.ConfigModel;/***
* @ClassName: Presentation
* @Description: TODO(生成表现层的代码)
* @author 于继伟
* @date 2017-10-22 上午10:06:05
**/
public class Presentation extends BaseExecutor {public void generate(){//1:从配置管理里面获取相应的配置信息ConfigModel cm = ConfigManager.getInstance().getConfigData();if(cm.isNeedGenPresentation()){//2:按照要求去生成相应的代码,并保存文件System.out.println("正在生成表现层代码文件");}}}

package com.bane.example2.executor;import com.bane.example2.config.ConfigManager;
import com.bane.example2.config.ConfigModel;/***
* @ClassName: Business
* @Description: TODO(生成业务层的代码文件)
* @author 于继伟
* @date 2017-10-22 上午10:08:37
**/
public class Business extends BaseExecutor{public void generate(){//1:从配置管理里面获取相应的配置信息ConfigModel cm = ConfigManager.getInstance().getConfigData();if(cm.isNeedGenBusiness()){//2:按照要求去生成相应的代码,并保存文件System.out.println("正在生成业务层代码");}}}

package com.bane.example2.executor;import com.bane.example2.config.ConfigManager;
import com.bane.example2.config.ConfigModel;/***
* @ClassName: Dao
* @Description: TODO(生成Dao层代码)
* @author 于继伟
* @date 2017-10-22 上午10:10:51
**/
public class Dao extends BaseExecutor{public void generate(){//1:从配置管理里面获取相应的配置信息ConfigModel cm = ConfigManager.getInstance().getConfigData();if(cm.isNeedGenPresentation()){//2:按照要求去生成相应的代码,并保存文件System.out.println("正在生成表现层代码文件");}}}

最后是我们的外观类:

package com.bane.example2.facade;import com.bane.example2.executor.Business;
import com.bane.example2.executor.Dao;
import com.bane.example2.executor.Presentation;/***
* @ClassName: Facade
* @Description: TODO(生成代码的外观类)
* @author 于继伟
* @date 2017-10-22 上午9:54:09
**/
public class Facade {/*** 构造方法私有化*/private Facade(){}/*** 集中调用子系统的方法*/public static void generate(){new Presentation().generate();new Business().generate();new Dao().generate();}}

主方法测试:

package com.bane.example2;import com.bane.example2.facade.Facade;/***
* @ClassName: Main
* @Description: TODO(主方法测试)
* @author 于继伟
* @date 2017-10-22 上午10:56:22
**/
public class Main {public static void main(String[] args) {Facade.generate();}}

控制台输出:

正在生成表现层代码文件
正在生成业务层代码
正在生成表现层代码文件

  从上面可以看出,我们的外观类的generate方法,管理着我们生成代码的一整套API,我们需要的时候直接调用就好,而配置管理模块则控制着我们代码生成的结果,不放在外观类中使用,这个模块相当于是一个管理模块配置功能,是为其他三个模块服务的。结合上一篇博客的工厂模式,我们是不是可以用工厂模式和外观模式结合起来搞一点事情呢?直接上代码:

其余的代码和上面都是一样的 我就不贴出来了,只是增加了一个工厂类,代码如下:

package com.bane.example3.factory;import com.bane.example3.facade.Facade;/***
* @ClassName: FacadeFactory
* @Description: TODO(外观模式工厂)
* @author 于继伟
* @date 2017-10-22 上午10:19:09
**/
public class FacadeFactory {private FacadeFactory(){}public static Facade createFacade(){return new Facade();}}

主方法测试:

package com.bane.example3;import com.bane.example3.facade.Facade;
import com.bane.example3.factory.FacadeFactory;/***
* @ClassName: Main
* @Description: TODO(主方法测试)
* @author 于继伟
* @date 2017-10-22 上午10:16:12
**/
public class Main {public static void main(String[] args) {Facade facade = FacadeFactory.createFacade();facade.generate();}}

控制台输出:

正在生成表现层代码文件
正在生成业务层代码
正在生成表现层代码文件

结合我们昨天所说的,使用工厂模式的好处是什么?是为了方便模块化管理,管理我们项目中一些具体类的行为以及他们之间的相互关系,现在我们是有一个生成代码的外观类,如果我们还有一个就像前面所说的组装电脑的模块,两个风马牛不相及的内容,可以使用工厂进行解耦。这样我们项目的开发和维护会变得更简单。

  外观模式的优点和缺点以及总结

说了这么多,那么外观模式的有点和缺点是什么?

  1.松散耦合

  2.简单易用

  3.更好的划分层次

  4.过多或者是不太合理的Facade也容易让人迷惑

外观模式的本质是什么?

  封装交互,简化调用

多设计原则的体现?

  体现了最少知识原则,也就是说我们不需要知道子系统或者模块的API,体现了一个黑盒的思想

那么我们应该什么时候使用外观模式?

  1.如果你希望一个复杂的子系统提供一个简单接口的时候,可以考虑使用外观模式,使用外观对象来实现大部分客户需要的功能,从而简化客户的使用。

    2.如果想要让客户程序和抽象类的实现部分松散耦合,可以考虑使用外观模式,使用外观对象来实现这个子系统与它的客户分离开来,从而提高子系统的独立性和可移植性

  3.如果构建多层结构的系统,可以考虑使用外观模式,使用外观对象作为每层的入口,这样可以简化层间调用,也可以松散层次之间的依赖关系。

转载于:https://www.cnblogs.com/yujiwei/p/7708398.html

(原创)我眼中的设计模式系列之外观模式(二)相关推荐

  1. 设计模式系列·抽象工厂模式

    前言 以小说的笔法写的设计模式系列文章,你绝对看得懂![首发于公众号:"聊聊代码"] 设计模式系列·王小二需求历险记(一) 设计模式系列·王小二需求历险记(二) 设计模式系列·封装 ...

  2. Java设计模式系列--责任链模式(应用)

    原文网址:Java设计模式系列--责任链模式(应用)_IT利刃出鞘的博客-CSDN博客 简介 说明 本文介绍Java设计模式中的责任链模式的一些使用场景. 责任链模式的好处 符合单一职责原则 每个功能 ...

  3. 设计模式系列之建造者模式构建实体类

    设计模式系列之建造者模式(Build Pattern)构建实体类 模式定义 建造者模式属于23种设计模式中的创建型模式,可以理解为创建对象的一种很好的方法. 所谓建造者模式就是**将组件和组件的组件过 ...

  4. 设计模式学习系列9 外观模式Facade

    1.概述 自己卖了一辆越野自行车,但毕竟不是自己定制的,买回来之后可能需要更改一下脚蹬,座皮,里程计数器或者刹车系统,假如将自行车看做一个整体系统,对我们而言使用的是自行车,然后我们对自己车构件的修改 ...

  5. Java描述设计模式(12):外观模式

    本文源码:GitHub·点这里 || GitEE·点这里 一.生活场景 1.场景描述 在移动互联网没有普及之前,去饭店吃饭的流程大致如下:选座位,排队,点菜,结账.后来移动互联网普及,通过手机APP就 ...

  6. 设计模式学习笔记——外观模式

    外观模式(Facade Pattern)隐藏系统的复杂性,并向客户端提供了一个客户端可以访问系统的接口.这种类型的设计模式属于结构型模式,它向现有的系统添加一个接口,来隐藏系统的复杂性. 这种模式涉及 ...

  7. [学习笔记]设计模式[6]-{适配器模式外观模式}

    设计原则 最少知识原则:只和你的密友谈话 这个原则的意思是,在系统设计的过程中,不要让太多的类耦合在一起,免得对系统一部分的修改会影响到其他部分.在设计系统之前,应该首先注意对象与对象之间的交互关系, ...

  8. 从王者荣耀看设计模式(十.外观模式)

    ##从王者荣耀看设计模式(外观模式) 一.简介 王者荣耀是由多人协同开发而成,每个人负责游戏的一个或多个子功能,一个完整的功能是由很多已开发的子功能组合成的.我们要玩游戏时,只需要打开王者荣耀APP, ...

  9. 设计模式之外观模式php,php设计模式(十五)外观模式

    外观模式又叫门面模式: 现在都是模块化开发了: 开发中很多时候都是在使用各种扩展包: 或者在外观模式中我们叫做子系统: 外观模式的作用就是减少子系统之间的耦合: 降低子系统的使用难度: 我们举个栗子: ...

最新文章

  1. mac webpack 版本_晓前端周刊 第48期:EMP面向未来微前端方案正式开源了!玩转 webpack,使你的打包速度提升 90%;...
  2. [C#泛型系列文章]
  3. c++程序的多文件组织
  4. python中的float和eval_python中eval和float_python中eval与json.loads对json的处理
  5. springmvc二十一:自定义类型转换器
  6. 如何清除浮动(float)所带来的影响
  7. sql视图 权限_MySQL数据库的SQL语言与视图
  8. 软件工程软件产品质量要求与评价_软件质量保证(Quality Assurance)中常见的活动...
  9. python模拟足球_使用K-Means算法划分亚洲国家的三个足球梯队
  10. 怎么手动升级更新ubuntu系统到最新版
  11. 开源工具软件XMusicDownloader——音乐下载神器
  12. 数据分析知识体系模型
  13. 教你如何购买阿里云香港服务器(教程)
  14. 互联网老辛2022年3月上旬社群精华
  15. 贪吃蛇大作战游戏——C语言
  16. rc时间常数定义_时间常数τ(tao)=RC和周期T有什么关系?
  17. 安徽省淮北市谷歌卫星地图下载
  18. Stanford CS224N: PyTorch Tutorial (Winter ‘21) —— 斯坦福CS224N PyTorch教程 (第二部分)
  19. 大数据用户画像实战之业务数据调研及ETL
  20. 计算机电源主线怎么接,电脑电源线接法,教您电脑电源线怎么接

热门文章

  1. idea运行springboot出现 Disconnected from the target VM, address: ‘127.0.0.1:xxxx‘, transport: ‘socket‘
  2. 为什么企业宁愿花 15K 重新招人,也不愿意花 10K 留住老测试员?
  3. 新鲜角度看问题:从Python角度解析Selenium原理
  4. android日历读取账号,android – Outlook – 读取另一个用户的日历
  5. linux memcache端口占用,Linux: memcache的安装和启动、停止、重启, 检查memcache server是否开启...
  6. string返回第n个字符_Programming in Lualua学习第13期 Lua字符串库
  7. average diffusion distance
  8. 从2D恢复出3D的数据
  9. 基于深度卷积神经网络的苹果叶片植物病理学疾病检测
  10. 高光谱提取薯叶特征波长