肝一肝设计模式【八】-- 外观模式
系列文章目录
肝一肝设计模式【一】-- 单例模式 传送门
肝一肝设计模式【二】-- 工厂模式 传送门
肝一肝设计模式【三】-- 原型模式 传送门
肝一肝设计模式【四】-- 建造者模式 传送门
肝一肝设计模式【五】-- 适配器模式 传送门
肝一肝设计模式【六】-- 装饰器模式 传送门
肝一肝设计模式【七】-- 代理模式 传送门
文章目录
- 系列文章目录
- 前言
- 一、外观模式是什么
- 二、外观模式中的角色
- 三、举个栗子
- 四、在开源框架中的使用
- 写在最后
前言
本节我们继续分析设计模式中的结构型模式,前文中我们已经分析了适配器模式、装饰器模式、代理模式,本节我们来学习一下——外观模式。
一、外观模式是什么
外观模式(Facade Pattern),它为复杂子系统提供了一个简单的接口,使得客户端可以更容易地使用该子系统,同时避免了直接访问子系统可能带来的复杂性。
外观模式的核心思想是为子系统提供一个高层次的接口,以便客户端可以通过这个接口访问子系统的功能,而无需了解子系统的内部实现细节。外观模式封装了子系统的复杂性,提供了一个简单的界面,使得客户端可以更加方便地使用子系统的功能。
二、外观模式中的角色
通常情况下,外观模式的实现需要创建一个外观类,该类将客户端的请求委派给子系统中的相应对象进行处理。外观类对客户端隐藏了子系统的复杂性,同时还可以为子系统提供额外的功能,以满足客户端的需求。
外观模式主要由三个角色:
- 外观(Facade):外观是外观模式的核心,它封装了子系统的复杂性,并为客户端提供一个简单的接口。外观类通常包含一个或多个操作方法,这些方法将客户端的请求委派给子系统中的相应对象进行处理。外观类还可以为客户端提供一些额外的功能,以便满足客户端的需求。
- 子系统(Subsystem):子系统是外观模式中的核心组成部分,它是指实现系统功能的一组类。子系统包含一些相互关联的类,这些类共同实现了系统的一些功能。在外观模式中,客户端通常不会直接访问子系统中的类,而是通过外观类来访问子系统。
- 客户端(Client):客户端是使用外观模式的应用程序的组成部分。客户端通过外观类来访问子系统中的功能,从而实现系统的需求。客户端并不了解子系统的内部实现细节,它只需要调用外观类中的方法即可完成所需功能。
三、举个栗子
又到了举例子环节,比如单独一个人去医院看病,往往会因为挂号、化验、取报告、收费、取药等这些流程搞得焦头烂额,当你刚刚花了半个小时排完队交完费,转头看到取药窗口的长队时,当下的我崩溃如下图。。
实际生活中像我经历的这种情况不在少数,而这就催生出一种服务叫陪诊服务,用户只需要专注看病这件事就行了,其他都交给陪诊员,这种形式的服务就和程序中外观模式的概念就很类似了
上代码:
我们把取报告、交费、取药这几个步骤当做子系统
public class StepA {public void getReport() {System.out.println("帮我取化验报告");}
}
public class StepB {public void pay() {System.out.println("帮我去交费");}
}
public class StepC {public void getMedicine() {System.out.println("帮我把药取回来");}
}
陪诊员相当于外观角色
public class AccompanyFacade {private StepA stepA;private StepB stepB;private StepC stepC;public AccompanyFacade() {stepA = new StepA();stepB = new StepB();stepC = new StepC();}public void work() {stepA.getReport();stepB.pay();stepC.getMedicine();}
}
客户端调用
public class FacadeClient {public static void main(String[] args) {AccompanyFacade facade= new AccompanyFacade();facade.work();}
}

四、在开源框架中的使用
SLF4J(Simple Logging Facade for Java)是一个常用的日志框架,它使用了外观模式来封装不同的日志实现库,提供了统一的接口供开发人员使用。SLF4J允许开发人员在代码中使用一致的日志API,而无需关注底层的日志实现细节。
SLF4J的核心组件是Logger接口,它定义了常见的日志方法,如debug()、info()、error()等。开发人员可以通过获取Logger实例并调用这些方法来记录日志。
SLF4J的外观模式实现的关键在于它提供了适配器(Adapter)和桥接(Bridge)两个重要的概念:
-
适配器(Adapter):SLF4J提供了适配器模块,例如slf4j-jdk14、slf4j-log4j12等,用于适配不同的日志实现库,将它们转换为SLF4J接口的调用。这样,开发人员可以使用SLF4J的接口,而实际的日志实现则由相应的适配器来负责。
-
桥接(Bridge):SLF4J还提供了桥接模块,例如jul-to-slf4j、log4j-to-slf4j等,用于将其他日志库的日志输出重定向到SLF4J接口。这样,即使在使用其他日志库的应用中,开发人员仍然可以通过SLF4J接口来统一管理日志。
通过适配器和桥接的机制,SLF4J实现了外观模式,封装了不同的日志实现库,提供了统一的日志接口供开发人员使用。这样,开发人员可以轻松切换和管理日志库,而无需修改大量的代码。
SLF4J本身只提供了日志接口和相关的适配器和桥接模块,实际的日志输出仍需要依赖具体的日志实现库,例如Logback、Log4j等。开发人员需要在项目中同时引入SLF4J和所选的日志实现库。
以下是SLF4J的部分源代码,展示了它的外观模式实现:
Logger接口:
public interface Logger {void debug(String message);void info(String message);void error(String message);// ...
}
LoggerFactory类:
public final class LoggerFactory {private LoggerFactory() {}public static Logger getLogger(Class<?> clazz) {// 获取适配器实例ILoggerFactory loggerFactory = getILoggerFactory();return loggerFactory.getLogger(clazz.getName());}private static ILoggerFactory getILoggerFactory() {// 返回适配器实例return StaticLoggerBinder.getSingleton().getLoggerFactory();}
}
StaticLoggerBinder类:
public class StaticLoggerBinder {private static final StaticLoggerBinder SINGLETON = new StaticLoggerBinder();private final ILoggerFactory loggerFactory = new MyLoggerFactory();public static final StaticLoggerBinder getSingleton() {return SINGLETON;}public ILoggerFactory getLoggerFactory() {return loggerFactory;}
}
适配器实现:
public class Log4jLoggerFactory implements ILoggerFactory {public Logger getLogger(String name) {return new Log4jLogger(org.apache.log4j.Logger.getLogger(name));}
}
在上述代码中,Logger接口定义了常见的日志方法,LoggerFactory类是获取Logger实例的工厂类。LoggerFactory通过调用getILoggerFactory()方法获取适配器实例,然后返回相应的Logger实例。
StaticLoggerBinder类是一个单例类,提供了getLoggerFactory()方法来获取适配器实例。在示例中,适配器实现为Log4jLoggerFactory,它实现了ILoggerFactory接口,并通过Log4j库来实现日志功能。
这样,当开发人员通过LoggerFactory.getLogger()获取Logger实例时,SLF4J会根据适配器的实现来选择相应的日志实现库,然后返回封装好的Logger实例。开发人员可以直接使用Logger接口的方法来记录日志,而无需关心具体的日志实现细节。
写在最后
外观模式的优点:
-
简化接口:外观模式通过提供一个统一的接口,将底层子系统的复杂性封装起来。这样,使用者只需要与外观对象交互,无需了解底层子系统的具体实现细节,简化了接口和调用过程。
-
提供易用性:外观模式可以为使用者提供一个简单而易用的接口,降低了学习和使用系统的难度。使用者无需深入了解系统的内部结构和复杂性,可以更快地上手和开发。
-
解耦和降低依赖:外观模式将系统的子系统和使用者之间进行解耦,通过外观对象进行交互。这样,子系统的变化不会影响到使用者,使用者只需要关注外观对象的接口,减少了依赖关系。
-
提供灵活性和可维护性:通过外观模式,可以隔离系统的变化和演化。当底层子系统发生变化时,只需要调整外观对象的实现,而不需要修改使用者的代码。这提供了灵活性和可维护性,降低了系统的耦合度。
外观模式的缺点:
-
违背开闭原则:外观模式的一个潜在缺点是当系统的需求变化时,可能需要修改外观对象的接口或实现。这可能导致外观对象的修改,违背了开闭原则。但通常情况下,外观模式的修改范围相对较小,不会对系统的其他部分产生太大影响。
-
可能引入性能问题:在某些情况下,外观模式可能会引入性能问题。由于外观对象需要处理复杂的子系统调用,可能会导致一定的性能开销。但在大多数情况下,这种开销是可以接受的,并且可以通过优化和缓存等技术进行改进。
相关文章:
肝一肝设计模式【八】-- 外观模式
系列文章目录 肝一肝设计模式【一】-- 单例模式 传送门 肝一肝设计模式【二】-- 工厂模式 传送门 肝一肝设计模式【三】-- 原型模式 传送门 肝一肝设计模式【四】-- 建造者模式 传送门 肝一肝设计模式【五】-- 适配器模式 传送门 肝一肝设计模式【六】-- 装饰器模式 传送门 肝…...
Maven uber-jar(带依赖的打包插件)maven-shade-plugin
文章目录 最基础的 maven-shade-plugin 使用生成可执行的 Jar 包 和 常用的资源转换类包名重命名打包时排除依赖与其他常用打包插件比较 本文是对 maven-shade-plugin 常用配置的介绍,更详细的学习请参照 Apache Maven Shade Plugin 官方文档 通过使用 maven-shade…...
MySQL基础(二十八)索引优化与查询优化
都有哪些维度可以进行数据库调优?简言之: 索引失效、没有充分利用到索引——索引建立关联查询太多JOIN (设计缺陷或不得已的需求)——SQL优化服务器调优及各个参数设置(缓冲、线程数等)———调整my.cnf。数据过多――分库分表 关于数据库调优的知识点非常分散。不同的DBMS&…...
初步认识性能测试和完成一次完整的性能测试
上一篇博文主要通过两个例子让测试新手了解一下测试思想,和在做测试之前应该了解人几点,那么我们在如何完成一次完整的性能测试呢? 测试报告是一次完整性能测试的体现,所以,这里我给出一个完整的性能测试报告ÿ…...
使用插件快速生成代码
使用插件快速生成代码 咋们常说,授人以鱼不如授人以渔,在这里给大家提供一些技巧性的东西,方便一些新手同学可以快速上手,同时,也提高我们的开发兴趣与开发热情! 主要讲什么呢,我们来学一学如何…...
FE_Vue学习笔记 插槽 slot
插槽分为匿名插槽、具名插槽、作用域插槽。子组件中: 匿名插槽只能有一个;可以有多个具名插槽;作用域插槽中可以有匿名插槽和具名插槽。 当项目中一个组件可以多次复用时,我们可以把这个组件封装成单独的.vue文件,从…...
单链表的成环问题
前言:链表成环问题不仅考察双指针的用法,该问题还需要一定的数学推理和分析能力,看似简单的题目实则细思缜密,值得斟酌~ 目录 1.问题背景引入-判断链表是否成环: 1.1.正解:快慢指针 1.2 STL的集合判重 …...
横截面收益率
横截面收益率指的是在经典资产定价模型中,在横截面上线性确定的一个与资产风险匹配的资产收益率。 横截面收益率的预测[1] (一)变量和方法 我们主要使用月度频率数据进行检验。交易数据和公司财务数据来自于CSMAR数据库。CSMAR数据库的收益率调整了送股、配股以及拆…...
C++解析JSON JSONCPP库的使用
首先去GitHub下载JSONCPP的源码: JSonCpp的源码 解压后得到:jsoncpp-master 文件夹 需要的是:jsoncpp-master\src\lib_json 目录下的所有文件和 jsoncpp-master\include\json 目录下的所有文件,在MFC工程目录下新建两个文件夹或…...
不会Elasticsearch标准查询语句,如何分析数仓数据?
1 Elasticsearch的查询语句 ES中提供了一种强大的检索数据方式,这种检索方式称之为Query DSL,Query DSL是利用Rest API传递JSON格式的请求体(Request Body)数据与ES进行交互,这种方式的丰富查询语法让ES检索变得更强大,更简洁。 1.1 查询预发 # GET /…...
获得GitHub Copilot并结合VS Code使用
一、什么是GitHub Copilot GitHub Copilot是一种基于AI的代码生成工具。它使用OpenAI的GPT(生成式预训练Transformer)技术来提供建议。它可以根据您正在编写的代码上下文建议代码片段甚至整个函数。 要使用GitHub Copilot,您需要在编辑器中…...
Java基础-判断和循环
1 流程控制语句 在一个程序执行的过程中,各条语句的执行顺序对程序的结果是有直接影响的。所以,我们必须清楚每条语句的执行流程。而且,很多时候要通过控制语句的执行顺序来实现我们想要的功能。 1.1 流程控制语句分类 顺序结构 判…...
ESP32 FreeRTOS学习总结
2023.5.11 FreeRTOS中文数据手册:https://www.freertos.org/zh-cn-cmn-s/RTOS.html 感谢以下两位B站UP主的教程:孤独的二进制、Michael_ee 1.Task 创建任务常用API: 任务函数描述xTaskCreate()使用动态的方法创建一个任务xTaskCreatePinne…...
uniapp打包ios保姆式教程【最新】
uniapp打包 打包方式ios打包一、前往官网登录二、添加证书 三、添加标识符(Identifiers)四、添加安装ios测试机(Devices)五、获取证书profile文件六、生成并下载p12文件七、开始打包 打包方式 安卓打包直接使用公共测试证书即可打包成功,简单方便,这里我…...
Thread线程学习(2) Linux线程的创建、终止和回收
目录 1.首先要了解什么是线程ID,以及它的作用是什么 2.创建线程 3.终止线程 4.回收线程 5.总结 在Linux系统中,线程是轻量级的执行单元,能够在同一个进程中并发执行。本文将介绍如何在Linux环境下创建、终止和回收线程,并提供…...
linux-项目部署软件安装
安装jdk 操作步骤: 1、使用FinalShell自带的上传工具将jdk的二进制发布包上传到Linux jdk-8u171-linux-x64.tar.gz 2、解压安装包,命令为tar -zxvf jdk-8u171-linux-x64.tar.gz -C /usr/local 3、配置环境变量,使用vim命令修改/etc/profile文…...
Vue3-黑马(三)
目录: (1)vue3-基础-计算属性 (2) vue3-基础-xhr-基本使用 (3)vue3-基础-xhr-promise改造 (1)vue3-基础-计算属性 上面有重复的代码,用计算属性࿰…...
标准C库函数fprintf(),sprintf(),snprintf()的函数使用方法(往文件中写入数据,将变量的值转换成字符串输出)
前言 如果,想要深入的学习标准C库中函数fprintf(),sprintf(),snprintf(),还是需要去自己阅读Linux系统中的帮助文档。 具体输入命令: man 3 fprintf/sprintf/snprintf即可查阅到完整的资料信息。 fprintf 函数 fprin…...
不到1分钟,帮你剪完旅行vlog,火山引擎全新 AI「神器」真的这么绝?
旅行时,想在社交平台发布一支精美的旅行 vlog,拍摄剪辑需要花费多长时间? 20 分钟?一小时?半天? 在火山引擎算法工程师眼里,可能 1 分钟都用不了,因为会有 AI 替你完成。 没错&#…...
MySQL的概念、编译安装,以及自动补全
一.数据库的基本概念 1、数据(Data) • 描述事物的符号记录 • 包括数字,文字,图形,图像,声音,档案记录等 • 以“记录”形式按统一的格式进行存储 2、表 • 将不同的记录组织在一起 • …...
【WiFi帧结构】
文章目录 帧结构MAC头部管理帧 帧结构 Wi-Fi的帧分为三部分组成:MAC头部frame bodyFCS,其中MAC是固定格式的,frame body是可变长度。 MAC头部有frame control,duration,address1,address2,addre…...
8k长序列建模,蛋白质语言模型Prot42仅利用目标蛋白序列即可生成高亲和力结合剂
蛋白质结合剂(如抗体、抑制肽)在疾病诊断、成像分析及靶向药物递送等关键场景中发挥着不可替代的作用。传统上,高特异性蛋白质结合剂的开发高度依赖噬菌体展示、定向进化等实验技术,但这类方法普遍面临资源消耗巨大、研发周期冗长…...
基于服务器使用 apt 安装、配置 Nginx
🧾 一、查看可安装的 Nginx 版本 首先,你可以运行以下命令查看可用版本: apt-cache madison nginx-core输出示例: nginx-core | 1.18.0-6ubuntu14.6 | http://archive.ubuntu.com/ubuntu focal-updates/main amd64 Packages ng…...
基于Uniapp开发HarmonyOS 5.0旅游应用技术实践
一、技术选型背景 1.跨平台优势 Uniapp采用Vue.js框架,支持"一次开发,多端部署",可同步生成HarmonyOS、iOS、Android等多平台应用。 2.鸿蒙特性融合 HarmonyOS 5.0的分布式能力与原子化服务,为旅游应用带来…...
STM32标准库-DMA直接存储器存取
文章目录 一、DMA1.1简介1.2存储器映像1.3DMA框图1.4DMA基本结构1.5DMA请求1.6数据宽度与对齐1.7数据转运DMA1.8ADC扫描模式DMA 二、数据转运DMA2.1接线图2.2代码2.3相关API 一、DMA 1.1简介 DMA(Direct Memory Access)直接存储器存取 DMA可以提供外设…...
el-switch文字内置
el-switch文字内置 效果 vue <div style"color:#ffffff;font-size:14px;float:left;margin-bottom:5px;margin-right:5px;">自动加载</div> <el-switch v-model"value" active-color"#3E99FB" inactive-color"#DCDFE6"…...
GitHub 趋势日报 (2025年06月08日)
📊 由 TrendForge 系统生成 | 🌐 https://trendforge.devlive.org/ 🌐 本日报中的项目描述已自动翻译为中文 📈 今日获星趋势图 今日获星趋势图 884 cognee 566 dify 414 HumanSystemOptimization 414 omni-tools 321 note-gen …...
JVM暂停(Stop-The-World,STW)的原因分类及对应排查方案
JVM暂停(Stop-The-World,STW)的完整原因分类及对应排查方案,结合JVM运行机制和常见故障场景整理而成: 一、GC相关暂停 1. 安全点(Safepoint)阻塞 现象:JVM暂停但无GC日志,日志显示No GCs detected。原因:JVM等待所有线程进入安全点(如…...
HarmonyOS运动开发:如何用mpchart绘制运动配速图表
##鸿蒙核心技术##运动开发##Sensor Service Kit(传感器服务)# 前言 在运动类应用中,运动数据的可视化是提升用户体验的重要环节。通过直观的图表展示运动过程中的关键数据,如配速、距离、卡路里消耗等,用户可以更清晰…...
AI病理诊断七剑下天山,医疗未来触手可及
一、病理诊断困局:刀尖上的医学艺术 1.1 金标准背后的隐痛 病理诊断被誉为"诊断的诊断",医生需通过显微镜观察组织切片,在细胞迷宫中捕捉癌变信号。某省病理质控报告显示,基层医院误诊率达12%-15%,专家会诊…...
