一. 定义与类型

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

类型:结构性

二. 使用场景

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

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

三. 优缺点

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

减少系统依赖,松散耦合

更好的划分访问层次

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

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

   不符合开闭原则

四. 相关设计模式

外观模式和中介者模式

外观模式和单例模式

外观模式和抽象工厂模式

五. 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. Django开发常见问题

    1.Django设置中文,和时区.静态文件指向 #========================================================== # 设置时区 注意注释上面的:L ...

  2. PyCharm5 破解汉化

    作者博文地址:https://www.cnblogs.com/liu-shuai/ 破解: 将下列序列号复制到软件激活界面即可破解. 43B4A73YYJ-eyJsaWNlbnNlSWQiOiI0M0 ...

  3. HDU 5446——Unknown Treasure——————【CRT+lucas+exgcd+快速乘+递推求逆元】

    Each test case starts with three integers n,m,k(1≤m≤n≤1018,1≤k≤10) on a line where k is the number o ...

  4. DB2去重复的几种方法

    DB2去重的几种方法 有两个意义上的重复记录,一是完全重复的记录,也即所有字段均重复的记录,二是部分关键字段重复的记录,比如Name字段重复,而其他字段不一定重复或都重复可以忽略. 例如下表:tabl ...

  5. 在项目引用里添加上对Microsoft Word 11.0 object library的引用

    private void button1_Click(object sender, System.EventArgs e) { //调用打开文件对话框获取要打开的文件WORD文件,RTF文件,文本文件 ...

  6. Redis数据类型(字符串)

    Redis存放的字符串为二进制是安全的.字符串长度支持到512M. incr 递增数字INCR key 当存储的字符串是整数时,redis提供了一个实用的命令INCR,其作用是让当前键值递增,并返回递 ...

  7. Windows和Linux执行Java代码的不同方式

    一.Windows 下编译并执行 Java 字节码文件(类文件) 1.编译 Hello.java 源码文件: java -d . Hello.java 2.执行 Hello.class 字节码文件: ...

  8. h5:erver-Sent Events

    对于一般的 Web 应用开发,大多数开发人员并不陌生.在 Web 应用中,浏览器和服务器之间使用的是请求 / 响应的交互模式.浏览器发出请求,服务器根据收到的请求来生成相应的响应.浏览器再对收到的响应 ...

  9. Javascript的map与forEach的区别

    原理: 高级浏览器支持forEach方法语法:forEach和map都支持2个参数:一个是回调函数(item,index,list)和上下文: forEach:用来遍历数组中的每一项:这个方法执行是没 ...

  10. Android - 看似内存泄漏,实则不是,记一次内存泄漏的案例分析

    APP中常常会存在内存泄漏的问题,一个简单的测试方法是,多次进入和退出同一页面(Activity),使用adb shell中的dumpsys meminfo com.android.settings ...