当前位置: 首页 > news >正文

肝一肝设计模式【八】-- 外观模式

系列文章目录

肝一肝设计模式【一】-- 单例模式 传送门
肝一肝设计模式【二】-- 工厂模式 传送门
肝一肝设计模式【三】-- 原型模式 传送门
肝一肝设计模式【四】-- 建造者模式 传送门
肝一肝设计模式【五】-- 适配器模式 传送门
肝一肝设计模式【六】-- 装饰器模式 传送门
肝一肝设计模式【七】-- 代理模式 传送门


文章目录

  • 系列文章目录
  • 前言
  • 一、外观模式是什么
  • 二、外观模式中的角色
  • 三、举个栗子
  • 四、在开源框架中的使用
  • 写在最后


前言

本节我们继续分析设计模式中的结构型模式,前文中我们已经分析了适配器模式、装饰器模式、代理模式,本节我们来学习一下——外观模式。


一、外观模式是什么

外观模式(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 常用配置的介绍&#xff0c;更详细的学习请参照 Apache Maven Shade Plugin 官方文档 通过使用 maven-shade…...

MySQL基础(二十八)索引优化与查询优化

都有哪些维度可以进行数据库调优?简言之: 索引失效、没有充分利用到索引——索引建立关联查询太多JOIN (设计缺陷或不得已的需求)——SQL优化服务器调优及各个参数设置(缓冲、线程数等)———调整my.cnf。数据过多――分库分表 关于数据库调优的知识点非常分散。不同的DBMS&…...

初步认识性能测试和完成一次完整的性能测试

上一篇博文主要通过两个例子让测试新手了解一下测试思想&#xff0c;和在做测试之前应该了解人几点&#xff0c;那么我们在如何完成一次完整的性能测试呢&#xff1f; 测试报告是一次完整性能测试的体现&#xff0c;所以&#xff0c;这里我给出一个完整的性能测试报告&#xff…...

使用插件快速生成代码

使用插件快速生成代码 咋们常说&#xff0c;授人以鱼不如授人以渔&#xff0c;在这里给大家提供一些技巧性的东西&#xff0c;方便一些新手同学可以快速上手&#xff0c;同时&#xff0c;也提高我们的开发兴趣与开发热情&#xff01; 主要讲什么呢&#xff0c;我们来学一学如何…...

FE_Vue学习笔记 插槽 slot

插槽分为匿名插槽、具名插槽、作用域插槽。子组件中&#xff1a; 匿名插槽只能有一个&#xff1b;可以有多个具名插槽&#xff1b;作用域插槽中可以有匿名插槽和具名插槽。 当项目中一个组件可以多次复用时&#xff0c;我们可以把这个组件封装成单独的.vue文件&#xff0c;从…...

单链表的成环问题

前言&#xff1a;链表成环问题不仅考察双指针的用法&#xff0c;该问题还需要一定的数学推理和分析能力&#xff0c;看似简单的题目实则细思缜密&#xff0c;值得斟酌~ 目录 1.问题背景引入-判断链表是否成环&#xff1a; 1.1.正解&#xff1a;快慢指针 1.2 STL的集合判重 …...

横截面收益率

横截面收益率指的是在经典资产定价模型中&#xff0c;在横截面上线性确定的一个与资产风险匹配的资产收益率。 横截面收益率的预测[1] (一)变量和方法 我们主要使用月度频率数据进行检验。交易数据和公司财务数据来自于CSMAR数据库。CSMAR数据库的收益率调整了送股、配股以及拆…...

C++解析JSON JSONCPP库的使用

首先去GitHub下载JSONCPP的源码&#xff1a; JSonCpp的源码 解压后得到&#xff1a;jsoncpp-master 文件夹 需要的是&#xff1a;jsoncpp-master\src\lib_json 目录下的所有文件和 jsoncpp-master\include\json 目录下的所有文件&#xff0c;在MFC工程目录下新建两个文件夹或…...

不会Elasticsearch标准查询语句,如何分析数仓数据?

1 Elasticsearch的查询语句 ES中提供了一种强大的检索数据方式,这种检索方式称之为Query DSL,Query DSL是利用Rest API传递JSON格式的请求体(Request Body)数据与ES进行交互&#xff0c;这种方式的丰富查询语法让ES检索变得更强大&#xff0c;更简洁。 1.1 查询预发 # GET /…...

获得GitHub Copilot并结合VS Code使用

一、什么是GitHub Copilot GitHub Copilot是一种基于AI的代码生成工具。它使用OpenAI的GPT&#xff08;生成式预训练Transformer&#xff09;技术来提供建议。它可以根据您正在编写的代码上下文建议代码片段甚至整个函数。 要使用GitHub Copilot&#xff0c;您需要在编辑器中…...

Java基础-判断和循环

1 流程控制语句 在一个程序执行的过程中&#xff0c;各条语句的执行顺序对程序的结果是有直接影响的。所以&#xff0c;我们必须清楚每条语句的执行流程。而且&#xff0c;很多时候要通过控制语句的执行顺序来实现我们想要的功能。 1.1 流程控制语句分类 ​ 顺序结构 ​ 判…...

ESP32 FreeRTOS学习总结

2023.5.11 FreeRTOS中文数据手册&#xff1a;https://www.freertos.org/zh-cn-cmn-s/RTOS.html 感谢以下两位B站UP主的教程&#xff1a;孤独的二进制、Michael_ee 1.Task 创建任务常用API&#xff1a; 任务函数描述xTaskCreate()使用动态的方法创建一个任务xTaskCreatePinne…...

uniapp打包ios保姆式教程【最新】

uniapp打包 打包方式ios打包一、前往官网登录二、添加证书 三、添加标识符(Identifiers)四、添加安装ios测试机(Devices)五、获取证书profile文件六、生成并下载p12文件七、开始打包 打包方式 安卓打包直接使用公共测试证书即可打包成功&#xff0c;简单方便&#xff0c;这里我…...

Thread线程学习(2) Linux线程的创建、终止和回收

目录 1.首先要了解什么是线程ID&#xff0c;以及它的作用是什么 2.创建线程 3.终止线程 4.回收线程 5.总结 在Linux系统中&#xff0c;线程是轻量级的执行单元&#xff0c;能够在同一个进程中并发执行。本文将介绍如何在Linux环境下创建、终止和回收线程&#xff0c;并提供…...

linux-项目部署软件安装

安装jdk 操作步骤&#xff1a; 1、使用FinalShell自带的上传工具将jdk的二进制发布包上传到Linux jdk-8u171-linux-x64.tar.gz 2、解压安装包&#xff0c;命令为tar -zxvf jdk-8u171-linux-x64.tar.gz -C /usr/local 3、配置环境变量&#xff0c;使用vim命令修改/etc/profile文…...

Vue3-黑马(三)

目录&#xff1a; &#xff08;1&#xff09;vue3-基础-计算属性 &#xff08;2&#xff09; vue3-基础-xhr-基本使用 &#xff08;3&#xff09;vue3-基础-xhr-promise改造 &#xff08;1&#xff09;vue3-基础-计算属性 上面有重复的代码&#xff0c;用计算属性&#xff0…...

标准C库函数fprintf(),sprintf(),snprintf()的函数使用方法(往文件中写入数据,将变量的值转换成字符串输出)

前言 如果&#xff0c;想要深入的学习标准C库中函数fprintf()&#xff0c;sprintf()&#xff0c;snprintf()&#xff0c;还是需要去自己阅读Linux系统中的帮助文档。 具体输入命令&#xff1a; man 3 fprintf/sprintf/snprintf即可查阅到完整的资料信息。 fprintf 函数 fprin…...

不到1分钟,帮你剪完旅行vlog,火山引擎全新 AI「神器」真的这么绝?

旅行时&#xff0c;想在社交平台发布一支精美的旅行 vlog&#xff0c;拍摄剪辑需要花费多长时间&#xff1f; 20 分钟&#xff1f;一小时&#xff1f;半天&#xff1f; 在火山引擎算法工程师眼里&#xff0c;可能 1 分钟都用不了&#xff0c;因为会有 AI 替你完成。 没错&#…...

MySQL的概念、编译安装,以及自动补全

一.数据库的基本概念 1、数据&#xff08;Data&#xff09; • 描述事物的符号记录 • 包括数字&#xff0c;文字&#xff0c;图形&#xff0c;图像&#xff0c;声音&#xff0c;档案记录等 • 以“记录”形式按统一的格式进行存储 2、表 • 将不同的记录组织在一起 • …...

<6>-MySQL表的增删查改

目录 一&#xff0c;create&#xff08;创建表&#xff09; 二&#xff0c;retrieve&#xff08;查询表&#xff09; 1&#xff0c;select列 2&#xff0c;where条件 三&#xff0c;update&#xff08;更新表&#xff09; 四&#xff0c;delete&#xff08;删除表&#xf…...

黑马Mybatis

Mybatis 表现层&#xff1a;页面展示 业务层&#xff1a;逻辑处理 持久层&#xff1a;持久数据化保存 在这里插入图片描述 Mybatis快速入门 ![在这里插入图片描述](https://i-blog.csdnimg.cn/direct/6501c2109c4442118ceb6014725e48e4.png //logback.xml <?xml ver…...

SciencePlots——绘制论文中的图片

文章目录 安装一、风格二、1 资源 安装 # 安装最新版 pip install githttps://github.com/garrettj403/SciencePlots.git# 安装稳定版 pip install SciencePlots一、风格 简单好用的深度学习论文绘图专用工具包–Science Plot 二、 1 资源 论文绘图神器来了&#xff1a;一行…...

Python:操作 Excel 折叠

💖亲爱的技术爱好者们,热烈欢迎来到 Kant2048 的博客!我是 Thomas Kant,很开心能在CSDN上与你们相遇~💖 本博客的精华专栏: 【自动化测试】 【测试经验】 【人工智能】 【Python】 Python 操作 Excel 系列 读取单元格数据按行写入设置行高和列宽自动调整行高和列宽水平…...

FFmpeg 低延迟同屏方案

引言 在实时互动需求激增的当下&#xff0c;无论是在线教育中的师生同屏演示、远程办公的屏幕共享协作&#xff0c;还是游戏直播的画面实时传输&#xff0c;低延迟同屏已成为保障用户体验的核心指标。FFmpeg 作为一款功能强大的多媒体框架&#xff0c;凭借其灵活的编解码、数据…...

线程同步:确保多线程程序的安全与高效!

全文目录&#xff1a; 开篇语前序前言第一部分&#xff1a;线程同步的概念与问题1.1 线程同步的概念1.2 线程同步的问题1.3 线程同步的解决方案 第二部分&#xff1a;synchronized关键字的使用2.1 使用 synchronized修饰方法2.2 使用 synchronized修饰代码块 第三部分&#xff…...

使用分级同态加密防御梯度泄漏

抽象 联邦学习 &#xff08;FL&#xff09; 支持跨分布式客户端进行协作模型训练&#xff0c;而无需共享原始数据&#xff0c;这使其成为在互联和自动驾驶汽车 &#xff08;CAV&#xff09; 等领域保护隐私的机器学习的一种很有前途的方法。然而&#xff0c;最近的研究表明&…...

2024年赣州旅游投资集团社会招聘笔试真

2024年赣州旅游投资集团社会招聘笔试真 题 ( 满 分 1 0 0 分 时 间 1 2 0 分 钟 ) 一、单选题(每题只有一个正确答案,答错、不答或多答均不得分) 1.纪要的特点不包括()。 A.概括重点 B.指导传达 C. 客观纪实 D.有言必录 【答案】: D 2.1864年,()预言了电磁波的存在,并指出…...

2.Vue编写一个app

1.src中重要的组成 1.1main.ts // 引入createApp用于创建应用 import { createApp } from "vue"; // 引用App根组件 import App from ./App.vue;createApp(App).mount(#app)1.2 App.vue 其中要写三种标签 <template> <!--html--> </template>…...

定时器任务——若依源码分析

分析util包下面的工具类schedule utils&#xff1a; ScheduleUtils 是若依中用于与 Quartz 框架交互的工具类&#xff0c;封装了定时任务的 创建、更新、暂停、删除等核心逻辑。 createScheduleJob createScheduleJob 用于将任务注册到 Quartz&#xff0c;先构建任务的 JobD…...