设计模式之外观/门面模式_炉边诗人的博客-程序员宝宝

技术标签: 架构  java程序员  后端开发  设计模式  软件开发  

0x01.定义与类型

  • 定义:又叫门面模式,提供了一个统一的接口,用来访问子系统中的一群接口
  • 外观模式定义了一个高层接口,让子系统更容易使用
  • 类型:结构型
  • UML类图

在这里插入图片描述

  • 门面模式是对系统复杂的关系处理做了一个封装,对外提供一个简单的接口,成员介绍:
    • 子系统:被门面模式封装的子系统,也是具体业务逻辑的细节
    • facade类:门面类,对子系统执行流程进行封装,对外开放功能接口,一般为单例对象。

0x02.适用场景

  • 子系统越来越复杂,增加外观模式提供简单调用接口
  • 构建多层系统结构,利用外观对象作为每层的入口,简化层间调用

0x03.优点

  • 简化了调用过程,无需了解深入子系统,防止带来风险
  • 减少系统依赖、松散耦合
  • 更好的划分访问层次
  • 符合迪米特法则,即最少知道原则

0x04.缺点

  • 增加子系统,需要修改门面类,容易引入风险。
  • 修改门面类,不符合开闭原则

0x05.样例代码

场景:假设积分兑换物品流程,一共有三部分别依赖三个子系统
1.积分校验系统,查看是否有资格。
2.积分支付系统,兑换礼物,扣减积分等。
3.物流系统,兑换礼物后,进行配送流程。

  • 如果不适用门面模式,需要在客户端进行三个步骤的调用,而门面封装后只需要使用门面类,下面具体代码实现:
/**
 * 礼物实体类
 */
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;
    }
}

/**
 * 支付子系统
 */
public class PointsPaymentService {
    
    public boolean pay(PointsGift pointsGift) {
    
        //扣减积分
        System.out.println("支付:" + pointsGift.getName() + " 积分成功!");
        return true;
    }
}

/**
 * 积分校验子系统
 */
public class QualifyService {
    

    public boolean isAvailable (PointsGift pointsGift) {
    
        System.out.println("校验" + pointsGift.getName() + "积分资格通过,库存通过");
        return true;
    }
}

/**
 * 物流子系统
 */
public class ShippingService {
    
    public String shipGift (PointsGift pointsGift) {
    
        //物流系统的对接逻辑
        System.out.println(pointsGift.getName() + "进入物流系统");
        return "666";
    }
}

/**
 * 扣减积分门面类
 */
public class GiftExchangeService {
    

    /**
     * 模拟注入
     */
    private QualifyService qualifyService = new QualifyService();
    private PointsPaymentService pointsPaymentService = new PointsPaymentService();
    private ShippingService shippingService = new ShippingService();

    //模拟注入,一开始就已经有了三个依赖的子系统
//    public void setQualifyService(QualifyService qualifyService) {
    
//        this.qualifyService = qualifyService;
//    }
//
//    public void setPointsPaymentService(PointsPaymentService pointsPaymentService) {
    
//        this.pointsPaymentService = pointsPaymentService;
//    }
//
//    public void setShippingService(ShippingService shippingService) {
    
//        this.shippingService = shippingService;
//    }

    public void giftExchange (PointsGift pointsGift) {
    
        if (qualifyService.isAvailable(pointsGift)) {
    
            //资格校验通过
            if (pointsPaymentService.pay(pointsGift)) {
    
                //如果支付积分成功
                String shippingOrderNo = shippingService.shipGift(pointsGift);
                System.out.println("物流订单号:" + shippingOrderNo);
            }
        }
    }
}
  • 测试与调用类
/**
 * 客户端与测试类
 */
public class Test {
    

    public static void main(String[] args) {
    
        PointsGift pointsGift = new PointsGift("连衣裙");
        GiftExchangeService giftExchangeService = new GiftExchangeService();

//        giftExchangeService.setQualifyService(new QualifyService());
//        giftExchangeService.setPointsPaymentService(new PointsPaymentService());
//        giftExchangeService.setShippingService(new ShippingService());

        giftExchangeService.giftExchange(pointsGift);
    }
}
  • 测试输出结果:
校验连衣裙积分资格通过,库存通过
支付:连衣裙 积分成功!
连衣裙进入物流系统
物流订单号:666
  • 样例UML

在这里插入图片描述

0x06.相关的设计模式

  • 外观模式和中介者模式
    • 外观模式关注的是外界和子系统直接的交互
    • 中介者模式关注的是子系统之间的交互
  • 外观模式和单例模式
    • 外观模式中外观对象可以做成单例对象来使用
  • 外观模式和抽象工厂模式
    • 外观类可以通过抽象工厂获取子系统实例
    • 子系统可以在内部对外观类进行屏蔽

0x07.源码中的外观模式

  • SpringJDBC中的:JdbcUtils是对JDBC的封装
  • MyBatis: Configuration中new开头的方法
  • Tomcat: RequestFacade类
  • Tomcat: Request类
  • Tomcat: ResponseFacade类
  • Tomcat: StandardSessionFacade类

0x08.代码地址

门面模式: https://github.com/sigmako/design-pattern/tree/master/facade

0x09.参考

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/Artisters/article/details/95761186

智能推荐

vue中结合element-ui的Pagination 分页组件写出后端给所有数据前端进行分页和有筛选条件的功能(前端数据分页)_badboy__biubiubiu的博客-程序员宝宝_前端分页加筛选

vue中结合element-ui的Pagination 分页组件写出后端给所有数据前端进行分页和有筛选条件的功能(前端数据分页)前言昨天接到后端的一个获取接口,产品有分页,至今搞不懂为何后端竟然说出让我惊讶好久的话我只能回复一个问号,后面就是各种的讨论了,好吧,对于性能我的看法是在前端分页的话肯定要在前端各种操作数据,如果数据量复杂(几百条应该还好吧),那肯定会导致渲染慢从而耗费大量的内存,...

2020-07-15_weixin_49335993的博客-程序员宝宝

标题学?通?精?难?化?懂?易?学易通难,通易精难。而化又难,易学易懂。读书破万卷,学易通难。下笔如有神,通易精难。而化又难,易学易懂。精神与意念集中,精神要集中意念。读书.集中.意念.精神。学之不讲是犹食而不知其味者也,虽多亦奚为。大匠诲人,必以规矩。君子无终食之间违仁,造次必于是,颠沛必于是。 及心宗、相宗之书,于西书当通。学?通?精?难?化?懂?易?孟子曰:“羿之教人射,必志于彀,学者亦必志于彀。大匠诲人必以规矩,学者亦必以规矩。”羿教人射箭,总是期望把弓拉满,学的人也总是期望把弓

解决caffe训练target_blobs.size ==source_layer.blobs_size(2 vs.1)_xidaoliang123的博客-程序员宝宝

说明:这是在caffe利用resnet网络训练二分类的问题遇到的,之所以采用caffe训练是因为使用的嵌入式设备只支持caffe和tensorflow的模型权重文件。1、首先采用的resnet50训练,搭建网络并加载权重,参考https://blog.csdn.net/m0_37357063/article/details/84726818制作自己的训练集和测试集。在csdnhttps://b...

ESP32-IDF开发实例-传感器模块编程-DS18B20数字温度传感器_视觉&物联智能的博客-程序员宝宝_espidf ds18b20

DS18B20温度传感器ESP32是一系列高度集成的、专为移动设备、可穿戴电子产品设计的物联网模块,其集成了天线开关、RF balun、功率放大器、低接收噪声放大器,滤波器、电源管理模块等,可以独立运行应用,也可以通过SPI/SDIO或I2C/UART接口为其他设备提供WiFi和蓝牙功能。1、硬件准备NodeMCU ESP32-S V3.0开发板一块带有WiFi功能的路由器DS18B20传感器模块一个杜邦线若干条数据线一条DS18B20传感器是常用的数字温度传感器,其基于单总线通讯,接

基于云的产品上线部署qqfarm_zy_xingdian的博客-程序员宝宝_ucenter-farm数据库8.0

云计算体验课——基于云的产品上线部署qqfarm讲师:行癫(庄曜)公司:北京千锋教育云计算+网络安全教学部一:项目准备1、准备一台云服务器2、使用finalshell远程连接云服务器3、操作之前重装服务器系统二:服务部署1、安装LNMP架构【N:nginx M:mysql P:php】安装数据库mysql【www.mysql.com】下载安装工具[[email protected]

c语言程序设计视频哪个好,苏州C语言程序设计班_大表哥姓王的博客-程序员宝宝

单片机C语言程序设计班一、培训宗旨:通过对C语言程序设计知识和技能的学习,达到能独立利用C语言进行单片机的程序设计和项目开发工作。二、培训内容:(一)学习内容:1、单片机组成、应用领域及开发特点;2、单片机结构和原理:包括51单片机的构成、微处理器及其时序、*小应用系统、地址分配、管脚功能、复位电路等;3、单片机的软件系统:C语言基础知识、单片机C语言编程技巧;4、单片机的内部编程:I/O控制、定...

随便推点

最简单的NP-hard问题_大蟒传奇的博客-程序员宝宝_nphard问题求解最好方法

前言本文介绍了最简单的NP-hard问题——数字分区问题,以及该问题的一个伪多项式解法和两个近似解法。数字分区问题讨论这样一个问题:给定一个正整数的多重集合 ,能否将划分为两个子集和,使得中元素的和与中元素的和相等?在数论和计算机科学中,该问题被称为是数字分区问题,尽管NP完全,但是却存在动态规划的解法能够在伪多项式时间内求解,并且在许多情况下,存在最佳或者是近似的解决方法。因此,这个问题也被称为...

如何实现select省市地区三级联动并回显_free_baby007的博客-程序员宝宝_vben select 联动

首先导入三个js文件(注:最后)显示:                省市区街道:                                                                                   拼接成:xx省-xx市-xx区的格式保存在后台,这里我保存的是对应的value值function submitF

USB传输原理_Lazyafei的博客-程序员宝宝_usb数据传输原理

转自:https://blog.csdn.net/aaronychen/article/details/3719412USB传输小节     首先,要明白两个观点。第一,USB总线上所有的事务(数据流传输)都是由USB Host主动发起,而USB设备永远永远都是只是被动地接收然后处理USB Host发来的各种各样的命令(要求)。第二,中断是USB Host和USB设备之间的信令员,US...

Template的使用方法_小小白努力中的博客-程序员宝宝

注意他要导入相关的jar包有jdbc、Druid、Template的相关jar包百度上就可以找到或者加Q:858689814找我要Druid.properties文件这个文件放src里面//驱动driverClassName=com.mysql.jdbc.Driver//地址url=jdbc:mysql://localhost:3306/db1//用户名userna...

Android Settings中System/Global/Secure_settings_global.xml_WLHG8PLUS的博客-程序员宝宝

Android Settings中System/Global/Secure一、 概述在Android启动之后,我们通常需要根据自己的一些需要来设置一些符合我们使用习惯的属性。例如:来电铃声、锁屏时间、日期格式等等。而这些属性的设置通常是有Settings为入口,通过SettingsProvider来进行的。SettingsProvider也是所有系统设置的管理者。在M(Android5.0)版本之前,SettingsProvider中系统设置是存储在settings.db数据库中;但是在L(Andr

textarea去掉滚动条_木木芳草的博客-程序员宝宝_el-textarea去除滚动条

<el-input type="textarea" autosize class="modify-ui" readonly ref='userInfo' v-model="noticeList"> </el-input>mounted方法中: this.$nextTick(() => {//滚动条显示问题

推荐文章

热门文章

相关标签