一. 定义与类型

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

类型:结构性

二. 使用场景

子系统越来越复杂,增加外观模式提供简单调用接口

构建多层系统结构,利用外观对象作为每层的入口,简化层间调用

三. 优缺点

优点:简化了调用过程,无需了解深入子系统,防止带来风险。

减少系统依赖,松散耦合

更好的划分访问层次

符合迪米特法则,即最少知道原则

缺点:增加子系统,扩展子系统行为容易引入风险

   不符合开闭原则

四. 相关设计模式

外观模式和中介者模式

外观模式和单例模式

外观模式和抽象工厂模式

五. Coding

假设一个场景,在商城中用积分退换商品时,有几个步骤:

(1) 校验:判断当前积分是否能够兑换商品

(2) 支付:使用积分支付兑换商品

(3)物流:将兑换的商品,送到目的地

在实际的场景中,一般正常的步骤是,用户直接用积分兑换商品,并没有校验,支付,物流等细节。而是提供了一个统一的兑换接口,来访问这些子系统。

/**
* @program: designModel
* @description: 积分礼物
* @author: YuKai Fan
* @create: 2018-12-17 10:11
**/
public class PointsGift {
private String name; public PointsGift(String name) {
this.name = name;
} public String getName() {
return name;
} public void setName(String name) {
this.name = name;
}
}
/**
* @program: designModel
* @description: 校验系统
* @author: YuKai Fan
* @create: 2018-12-17 10:12
**/
public class QualifyService {
public boolean isAvailable(PointsGift pointsGift) {
System.out.println("校验" + pointsGift.getName() + " 积分资格通过,库存通过");
return true;
}
}
/**
* @program: designModel
* @description: 校验系统
* @author: YuKai Fan
* @create: 2018-12-17 10:12
**/
public class QualifyService {
public boolean isAvailable(PointsGift pointsGift) {
System.out.println("校验" + pointsGift.getName() + " 积分资格通过,库存通过");
return true;
}
}
/**
* @program: designModel
* @description: 积分支付系统
* @author: YuKai Fan
* @create: 2018-12-17 10:13
**/
public class PoingtsPaymentService {
public boolean pay(PointsGift pointsGift) {
//扣减积分
System.out.println("支付" + pointsGift.getName() + " 积分成功");
return true;
}
}
/**
* @program: designModel
* @description: 物流系统
* @author: YuKai Fan
* @create: 2018-12-17 10:15
**/
public class ShippingService {
public String shipGift(PointsGift pointsGift) {
//物流系统的对接逻辑
System.out.println(pointsGift.getName() + "进入物流系统");
String shippingOrderNo = "666";
return shippingOrderNo;
}
}

统一对外开放的接口

/**
* @program: designModel
* @description: 礼物兑换
* @author: YuKai Fan
* @create: 2018-12-17 10:17
**/
public class GiftExchangeService {
private QualifyService qualifyService;
private PoingtsPaymentService poingtsPaymentService ;
private ShippingService shippingService; public void giftExchange(PointsGift pointsGift) {
if (qualifyService.isAvailable(pointsGift)) {
//资格校验通过
if (poingtsPaymentService.pay(pointsGift)) {
//如果支付积分成功
String shippingOrderNo = shippingService.shipGift(pointsGift);
System.out.println("物流系统下班成功,订单号:" + shippingOrderNo);
}
}
} public QualifyService getQualifyService() {
return qualifyService;
} public void setQualifyService(QualifyService qualifyService) {
this.qualifyService = qualifyService;
} public PoingtsPaymentService getPoingtsPaymentService() {
return poingtsPaymentService;
} public void setPoingtsPaymentService(PoingtsPaymentService poingtsPaymentService) {
this.poingtsPaymentService = poingtsPaymentService;
} public ShippingService getShippingService() {
return shippingService;
} public void setShippingService(ShippingService shippingService) {
this.shippingService = shippingService;
}
}

客户端:

/**
* @program: designModel
* @description:
* @author: YuKai Fan
* @create: 2018-12-17 10:21
**/
public class Test {
public static void main(String[] args) {
PointsGift pointsGift = new PointsGift("T shirt");
GiftExchangeService giftExchangeService = new GiftExchangeService(); giftExchangeService.setQualifyService(new QualifyService());
giftExchangeService.setPoingtsPaymentService(new PoingtsPaymentService());
giftExchangeService.setShippingService(new ShippingService()); giftExchangeService.giftExchange(pointsGift);
}
}

UML类图:

看上面的UML类图,应用层与子系统依旧存在着联系,这是因为没有集成spring的依赖注入的原因,而是直接在应用层中创建了子系统的对象注入到外观对象中。

进一步完善后的代码:

/**
* @program: designModel
* @description: 礼物兑换
* @author: YuKai Fan
* @create: 2018-12-17 10:17
**/
public class GiftExchangeService {
private QualifyService qualifyService = new QualifyService();
private PoingtsPaymentService poingtsPaymentService = new PoingtsPaymentService();
private ShippingService shippingService = new ShippingService(); public void giftExchange(PointsGift pointsGift) {
if (qualifyService.isAvailable(pointsGift)) {
//资格校验通过
if (poingtsPaymentService.pay(pointsGift)) {
//如果支付积分成功
String shippingOrderNo = shippingService.shipGift(pointsGift);
System.out.println("物流系统下班成功,订单号:" + shippingOrderNo);
}
}
} public QualifyService getQualifyService() {
return qualifyService;
} public void setQualifyService(QualifyService qualifyService) {
this.qualifyService = qualifyService;
} public PoingtsPaymentService getPoingtsPaymentService() {
return poingtsPaymentService;
} public void setPoingtsPaymentService(PoingtsPaymentService poingtsPaymentService) {
this.poingtsPaymentService = poingtsPaymentService;
} public ShippingService getShippingService() {
return shippingService;
} public void setShippingService(ShippingService shippingService) {
this.shippingService = shippingService;
}
}
/**
* @program: designModel
* @description:
* @author: YuKai Fan
* @create: 2018-12-17 10:21
**/
public class Test {
public static void main(String[] args) {
PointsGift pointsGift = new PointsGift("T shirt");
GiftExchangeService giftExchangeService = new GiftExchangeService(); // giftExchangeService.setQualifyService(new QualifyService());
// giftExchangeService.setPoingtsPaymentService(new PoingtsPaymentService());
// giftExchangeService.setShippingService(new ShippingService()); giftExchangeService.giftExchange(pointsGift);
}
}

UML类图:

上面的新类图,才是真正的外观模式的结构类图,支持了迪米特法则。

在开发过程中,要注意应用层到底有没有与子系统发生关系,要是又有了一个新的子系统,那就不符合开闭原则了。如果这个系统以后不需要扩展,或者扩展的子系统非常有限,那就用实体外观类就可以了,可以减少复杂度。但是如果需要经常新加子系统,那就需要使用抽象外观类。

六. 源码分析

springjdbc中的closeConnection(),closeStatement(),closeResultSet()等方法

mybatis中的Configuration配置类,使用的也是外观模式思想

tomcat源码中RequestFacade是一个request的一个外观类,实现了HttpServletRequest接口,

  还有一个Request类也实现了HttpServletRequest接口,在request里声明了RequestFacade对象,而且具体的操作都是用的这个对象

  tomcat源码中大量的使用了外观类

java设计模式——外观模式(门面模式)的更多相关文章

  1. 外观模式 门面模式 Facade 结构型 设计模式(十三)

    外观模式(FACADE) 又称为门面模式   意图 为子系统中的一组接口提供一个一致的界面 Facade模式定义了一个高层接口,这一接口使得这一子系统更加易于使用. 意图解析 随着项目的持续发展,系统 ...

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

    JAVA 设计模式 外观模式 用途 外观模式 (Facade) 为子系统中的一组接口提供一个一致的界面,此模式定义了一个高层接口,这个接口使得这一子系统更加容易使用. 外观模式是一种结构型模式. 结构

  3. 【设计模式】Java设计模式 - 外观模式

    Java设计模式 - 外观模式 不断学习才是王道 继续踏上学习之路,学之分享笔记 总有一天我也能像各位大佬一样 原创作品,更多关注我CSDN: 一个有梦有戏的人 准备将博客园.CSDN一起记录分享自己 ...

  4. 设计模式在实际业务应用中的介绍之3——外观或门面模式Facade对AOP装配业务工厂的应用

    在C#中实现的基于外观或门面模式打造的业务应用案例 以前一直没有想过写一些东西来把项目中用到的知识点及技术实现做一个归纳整理并分享出来.现在打算逐渐的把项目中的一些东西整理并分享出来,与大家共勉! 外 ...

  5. 重学 Java 设计模式:实战代理模式「模拟mybatis-spring中定义DAO接口,使用代理类方式操作数据库原理实现场景」

    作者:小傅哥 博客:https://bugstack.cn 沉淀.分享.成长,让自己和他人都能有所收获! 一.前言 难以跨越的瓶颈期,把你拿捏滴死死的! 编程开发学习过程中遇到的瓶颈期,往往是由于看不 ...

  6. 重学 Java 设计模式:实战迭代器模式「模拟公司组织架构树结构关系,深度迭代遍历人员信息输出场景」

    作者:小傅哥 博客:https://bugstack.cn - 原创系列专题文章 沉淀.分享.成长,让自己和他人都能有所收获! 一.前言 相信相信的力量! 从懵懂的少年,到拿起键盘,可以写一个Hell ...

  7. 重学 Java 设计模式:实战备忘录模式「模拟互联网系统上线过程中,配置文件回滚场景」

    作者:小傅哥 博客:https://bugstack.cn - 原创系列专题文章 沉淀.分享.成长,让自己和他人都能有所收获! 一.前言 实现不了是研发的借口? 实现不了,有时候是功能复杂度较高难以实 ...

  8. 重学 Java 设计模式:实战状态模式「模拟系统营销活动,状态流程审核发布上线场景」

    作者:小傅哥 博客:https://bugstack.cn - 原创系列专题文章 沉淀.分享.成长,让自己和他人都能有所收获! @ 目录 一.前言 二.开发环境 三.状态模式介绍 四.案例场景模拟 1 ...

  9. 重学 Java 设计模式:实战访问者模式「模拟家长与校长,对学生和老师的不同视角信息的访问场景」

    作者:小傅哥 博客:https://bugstack.cn - 原创系列专题文章 沉淀.分享.成长,让自己和他人都能有所收获! 一.前言 能力,是你前行的最大保障 年龄会不断的增长,但是什么才能让你不 ...

  10. Java 设计模式泛谈&装饰者模式和单例模式

    设计模式(Design Pattern) 1.是一套被反复使用.多人知晓的,经过分类编目 的 代码设计经验总结.使用设计模式是为了可重用代码,让代码更容易维护以及扩展. 2.简单的讲:所谓模式就是得到 ...

随机推荐

  1. hashcode详解--转发

    序言 写这篇文章是因为在看hashMap源码时遇到有什么hashcode值,然后就去查,脑袋里面是有映像的,不就是在Object中有equals和hashcode方法嘛,这在学java基础的时候就遇到 ...

  2. 事务(JDBC、Spring)

    如果不用spring管理事务,我们自己写代码来操作事务.那么这个代码怎么写要看底层怎么访问数据库了. 当采用原生JDBC访问数据库时,操作事务需要使用java.sql.Connection的API.开 ...

  3. volatile的作用和原理

    1.保持内存可见性内存可见性:所有线程都能看到共享内存的最新状态.每次读取前必须先从主内存刷新最新的值.每次写入后必须立即同步回主内存当中.Java通过几种原子操作完成工作内存和主内存的交互:lock ...

  4. Django-1 简介

    1.1 MVC与MTV模型 MVCWeb服务器开发领域里著名的MVC模式,所谓MVC就是把Web应用分为模型(M),控制器(C)和视图(V)三层,他们之间以一种插件式的.松耦合的方式连接在一起,模型负 ...

  5. python 横向比较最大值 贴标签

    df['dfda']=pd.Series(df[['a','b','v']].idxmax(axis=1),index=df.index)#横向比较最大值并返回列名,比循环快N倍

  6. 性能测试工具LoadRunner27-LR之读取Excel数据

    为何要读取Excel数据? 很多用户喜欢用Excel来统计数据,比如学生成绩表.个人信息等.有时需要把Excel中的数据来进行参数化,数据量比较多时,一个个在LR里输入是不现实的,因此需要用LR来导入 ...

  7. mysql 8 修改root 密码

    主要参考:https://dev.mysql.com/doc/refman/8.0/en/resetting-permissions.html 需要注意的是创建文件的时候需要保存为 utf-8 无 B ...

  8. pat04-树9. Path in a Heap (25)

    04-树9. Path in a Heap (25) 时间限制 150 ms 内存限制 65536 kB 代码长度限制 8000 B 判题程序 Standard 作者 CHEN, Yue Insert ...

  9. pat1016. Phone Bills (25)

    1016. Phone Bills (25) 时间限制 400 ms 内存限制 65536 kB 代码长度限制 16000 B 判题程序 Standard 作者 CHEN, Yue A long-di ...

  10. GitKraken使用教程-基础部分(9)

    10.  合并分支并解决冲突(conflict) 1) 合并分支 在代码管理过程中,切换分支或者同步服务器代码时,常常会出现代码冲突的情况,这种情况出现的原因一般是由于两个分支对同一个文件进行修改, ...