java设计模式之:外观模式

news2024/11/26 0:36:08

前言

举个现实生活中例子,泡茶和去茶馆喝茶的区别,如果是自己泡茶需要自行准备茶叶、茶具和开水,而去茶馆喝茶,最简单的方式就是跟茶馆服务员说想要一杯什么样的茶,是铁观音、碧螺春还是西湖龙井?正因为茶馆有服务员,顾客无须直接和茶叶、茶具、开水等交互,整个泡茶过程由服务员来完成,顾客只需与服务员交互即可,整个过程非常简单省事。

以上这种场景类似设计模式中的外观模式,也叫做门面模式。外观模式通过引入一个新的外观类来实现该功能,外观类充当了“服务员”的角色,它为多个业务类的调用提供了一个统一的入口,简化了类与类之间的交互。本文我们一起来聊聊外观模式。

外观模式介绍

外观模式是一种使用频率非常高的结构型设计模式,它通过引入一个外观角色来简化客户端与子系统之间的交互,为复杂的子系统调用提供一个统一的入口,降低子系统与客户端的耦合度,且客户端调用非常方便。

外观模式结构图:

image.png

(1) Facade(外观角色):在客户端可以调用它的方法,在外观角色中可以知道相关的(一个或者多个)子系统的功能和责任;在正常情况下,它将所有从客户端发来的请求委派到相应的子系统去,传递给相应的子系统对象处理。

(2) SubSystem(子系统角色):在软件系统中可以有一个或者多个子系统角色,每一个子系统可以不是一个单独的类,而是一个类的集合,它实现子系统的功能;每一个子系统都可以被客户端直接调用,或者被外观角色调用,它处理由外观类传过来的请求;子系统并不知道外观的存在,对于子系统而言,外观角色仅仅是另外一个客户端而已。

案例场景

场景一:自己泡茶,整个过程应该是“烧开水->拿茶具->泡茶叶”然后喝茶。

image.png

定义一个饮用水类:DrinkableWater

/**
 * 烧水
 */
public class DrinkableWater {

    public DrinkableWater(){
        System.out.println("水准备好了");
    }

    //烧水
    public void facadeWater(){
        System.out.println("水烧开了");
    }
}

定义一个茶叶类:Tea

/**
 * 茶叶
 */
public class Tea {

    public Tea(){
        System.out.println("茶叶准备好了");
    }

    //取茶
    public void facadeTea(){
        System.out.println("可以泡茶了");
    }
}

定义一个茶杯类:TeaCup

/**
 * 茶杯
 */
public class TeaCup {

    public TeaCup(){
        System.out.println("茶杯准备好了");
    }

    //泡茶
    public void facadeTeaCup(Tea tea){
        tea.facadeTea();
        System.out.println("茶叶泡进茶杯了");
        System.out.println("茶冲好了");
    }
}

准备就绪,开始泡茶

public static void main(String[] args) {
    System.out.println("准备泡茶...");
    DrinkableWater drinkableWater = new DrinkableWater();
    TeaCup teaCup = new TeaCup();
    Tea tea = new Tea();

    drinkableWater.facadeWater();
    teaCup.facadeTeaCup(tea);
    System.out.println("喝茶...");
}

运行结果

准备泡茶...
水准备好了
茶杯准备好了
茶叶准备好了
水烧开了
可以泡茶了
茶叶泡进茶杯了
茶冲好了
喝茶...

场景二:去茶馆喝茶,不用自己动手泡茶了,直接告诉茶馆的服务员就行了。

image.png

定义一个服务员类:

/**
 * 服务员
 */
public class Waiter {

    private DrinkableWater drinkableWater = new DrinkableWater();
    private TeaCup teaCup = new TeaCup();
    private Tea tea = new Tea();

    //获得一杯茶
    public void getTea(){
        drinkableWater.facadeWater();
        teaCup.facadeTeaCup(tea);
    }
}

客户类:Customer

public class Customer {

    public static void main(String[] args) {
        //叫店小二
        Waiter waiter = new Waiter();
        //从店小二那获得一杯茶
        waiter.getTea();
    }
}

运行结果

水准备好了
茶杯准备好了
茶叶准备好了
水烧开了
可以泡茶了
茶叶泡进茶杯了
茶冲好了

在上面的泡茶的例子中,客人就是客户角色,茶馆服务员就是门面角色,茶具、饮用水、茶叶就是子系统角色。

代码看上去都很简单,也许你感觉二者区别不是很大,假如在软件开发中三个子系统之间有先后顺序,还有来自不同网络开销,我们通过门面模式提供的方法,就屏蔽了这些差异,让我们只需要调用门面角色提供给我们的方法即可。

外观模式优点

  1. 减少系统的相互依赖

如果我们不使用门面模式, 外界访问直接深入到子系统内部, 相互之间是一种强耦合关系, 你死我就死, 你活我才能活, 这样的强依赖是系统设计所不能接受的, 门面模式的出现就很好地解决了该问题, 所有的依赖都是对门面对象的依赖, 与子系统无关。

  1. 提高安全性

想让你访问子系统的哪些业务就开通哪些逻辑, 不在门面上开通的方法, 你休想访问到。

外观模式缺点

  1. 不能很好地限制客户端直接使用子系统类,如果对客户端访问子系统类做太多的限制则减少了可变性和灵活性。

  2. 如果设计不当,增加新的子系统可能需要修改外观类的源代码,违背了开闭原则。

外观模式应用场景

  1. 解决易用性问题

门面模式可以用来封装系统的底层实现,隐藏系统的复杂性,提供一组更加简单易用、更高层的接口。

  1. 解决性能问题

通过将多个接口调用替换为一个门面接口调用,减少网络通信成本,提高客户端的响应速度。

  1. 解决分布式事务问题

需要调用多个子系统的接口方法,而这些接口要么都成功,要么都失败,我们就可以利用门面模式包裹这些子系统接口,然后通过某种方法保证这些接口在一个事务中完成。

总结

在几乎所有的软件中都能够找到外观模式的应用,如绝大多数B/S系统都有一个首页或者导航页面,大部分C/S系统都提供了菜单或者工具栏,在这里,首页和导航页面就是B/S系统的外观角色,而菜单和工具栏就是C/S系统的外观角色,通过它们用户可以快速访问子系统,降低了系统的复杂程度。所有涉及到与多个业务对象交互的场景都可以考虑使用外观模式进行重构。

很多时候不是设计模式没有用,而是自己编程开发经验不足导致即使学了设计模式也很难驾驭。毕竟这些知识都是经过一些实际操作提炼出来的精华。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/643897.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

互斥锁、自旋锁、读写锁、悲观锁、乐观锁的应用场景

多线程访问共享资源的时候,避免不了资源竞争而导致数据错乱的问题,所以我们通常为了解决这一问题,都会在访问共享资源之前加锁。 最常用的就是互斥锁,当然还有很多种不同的锁,比如自旋锁、读写锁、乐观锁等&#xff0…

数据结构——树和二叉树

文章目录 **一 数的基本概念****1 定义****2 基本术语****3 树的性质** **二 二叉树的概念****1 二叉树的定义和特性****1.1 定义****1.2 特殊的二叉树****1.3 二叉树的性质** **2 二叉树的存储结构****2.1 顺序存储结构****2.2 链式存储结构** **三 二叉树的遍历和线索二叉树*…

Spark SQL数据源的基本操作(更新ing)

文章目录 一、基本操作二、默认数据源(一)默认数据源Parquet(二)案例演示读取Parquet文件1、在Spark Shell中演示练习1、将student.txt文件转换成student.parquet练习2、读取student.parquet文件得到学生数据帧,并显示…

K8S minikube本地安装

一. mac安装K8S 1.brew安装 brew install kubectl 2.查看版本 kubectl version --outputjson { "clientVersion": { "major": "1", "minor": "27", "gitVersion": "v1.27.2", &…

基于深度学习的高精度奶牛检测识别系统(PyTorch+Pyside6+YOLOv5模型)

摘要:基于深度学习的高精度奶牛检测识别系统可用于日常生活中或野外来检测与定位奶牛目标,利用深度学习算法可实现图片、视频、摄像头等方式的奶牛目标检测识别,另外支持结果可视化与图片或视频检测结果的导出。本系统采用YOLOv5目标检测模型…

locked勒索病毒利用零日漏洞,企业服务器数据瞬间遭受致命加密

目录 引言: 事件概述: .locked勒索病毒加密算法: 数据恢复建议: locked勒索病毒数据恢复案例: 什么叫零日漏洞? 对策建议: 引言: 近日,网络安全界再次爆发了一起…

RK3588平台开发系列讲解(系统篇)开机启动原因

文章目录 一、系统开机启动原因二、开机启动场景沉淀、分享、成长,让自己和他人都能有所收获!😄 📢本篇章主要讲解平台系统开机启动原因介绍。 一、系统开机启动原因 开机原因记录文件在/proc/sys/kernel/boot_reason,那么开机后可以从这个文件中读取数值来获知本次开机…

锁升级:无锁、偏向锁、轻量级锁、重量级锁

锁升级 JDK 1.6之前,synchronized 还是一个重量级锁,是一个效率比较低下的锁。但是在JDK 1.6后,JVM为了提高锁的获取与释放效率对synchronized 进行了优化,引入了偏向锁和轻量级锁 ,从此以后锁的状态就有了四种&#…

开源SCRM营销平台MarketGo-数据管理

一、概述 企业在私域运营的场景下,系统在运行中会产生一些用户数据和行为数据。 用户数据包含年龄,性别,生日,电话,用户标签,还有用户和员工的关系等信息。行为数据包含在SCRM中创建活动的用户事件&#…

自学黑客(网络安全)?一般人我劝你还是算了吧!

前言 博主本人 18年就读于一所普通的本科学校,21年 6 月在三年经验的时候顺利通过校招实习面试进入大厂,现就职于某大厂安全联合实验室。 我为啥说自学黑客(网络安全),一般人我还是劝你算了吧。因为我就是那个不一般的…

【C++】c++11的新特性——右值引用/移动语义/lambda表达式

文章目录 C11介绍1. 统一的列表初始化1.1 {}初始化1.2 std::initializer_list 2. 一些关键字2.1 auto2.2 decltype2.3 nullptr 3. 范围for4. 右值引用和移动语义(重点)4.1 左值引用和右值引用4.2 右值引用的应用4.3 总结 5. 万能引用和完美转发6. 新的类…

mysql小表驱动大表

摘要: 小表驱动大表为了减少匹配时的数据量 判断谁做小表时,是比较算上过滤条件后的数量 left join时手动设置小表驱动大表 inner join时优化器会自动小表驱动大表 course–100条数据 student_info–100w条数据 优化器会选择小表驱动大表(这里…

使用VMware Workstation一步一步安装Rocky Linux 9

目录 目录 背景 准备阶段 新建虚拟机 安装Rocky Linux 进入系统 背景 Rocky Linux 简介 企业Linux,社区方式。 Rocky Linux是一个开源的企业操作系统,旨在与红帽企业Linux100%兼容。社区正在大力发展。 Rocky Linux 9.2 于2023年5月16日发布&a…

计算机组成原理(六)指令系统

一、指令的基本格式 1.1机器指令的相关概念 指令集(Instruction Set) 某机器所有机器指令的集合 *定长指令集 指令集中的所有指令长度均相同!取指令控制简单*不定长指令集 指令集中的所有指令长度有长、有短 操作码 (1)长度固定 用于指令字长较长的情况RISC 如IBM370操作码8位…

第四章 Linux网络编程 4.1 网络结构模式 4.2MAC地址、IP地址、端口

第四章 Linux网络编程 4.1 网络结构模式 C/S结构 简介 服务器 - 客户机,即 Client - Server(C/S)结构。C/S 结构通常采取两层结构。服务器负责数据的管理,客户机负责完成与用户的交互任务。客户机是因特网上访问别人信息的机器…

Ubuntu16.04.7+Qt15.5.0环境配置(一条龙讲解)

目录 1、下载并安装Ubuntu 2、Qt下载与安装 3、Qt环境配置 4、设置编译套件 5、创建qt快速启动脚本 1、下载并安装Ubuntu Ubuntu16.04.7下载链接https://releases.ubuntu.com/xenial/ 安装步骤省略。 2、Qt下载与安装 在Qt5.15之后的版本,官方都不提供离线安装…

Allegro因为精度问题导致走线连接不上的解决办法

Allegro因为精度问题导致走线连接不上的解决办法 在用Allegro做PCB设计的时候,尤其是从其它单板上导数据过来的时候,有时会因为精度不一致导致连接不上,如下图 线和过孔因为精度有微小的连接偏差 一般来说,可以逐个重新连接一下,但是如果连接点位比较多的话,需要花费较多…

在windos中同时使用gitee与github

1.为什么这样做? 原因非常简单,我们遇到自己喜欢的git仓库后,通常会将他们克隆到我们本地电脑上,但这个时候会有一个问题,就是我们喜欢的仓库有可能是gitee仓库,也有可能是github仓库,这个时候…

Windows YOLO v8训练自己的数据集

YOLO v8 训练自己的数据集 环境准备YOLO v8创建自己的数据集1.首先准备了VOC 格式的数据集2.然后确定用于训练、测试的数据3.将VOC格式标注转为YOLO 标注4.配置数据文件 yaml 配置 YOLO v8安装和训练安装依赖包训练 环境准备 这里我的环境是Windows 环境 YOLO v8 下载链接&a…

dma-fence使用demo

dma-fence是内核中一种比较常用的同步机制,本身的实现和使用并不复杂,其只有两种状态signaled和unsignaled。可能正是因为其本身的精简,在融入其他概念中时,在不同的环境下,赋予了dma-fence不同的含义。所以通常需要根据dma-fence…