Spring Boot + Facade Pattern : 通过统一接口简化多模块业务
文章目录
- Pre
- 概述
- 在编程中,外观模式是如何工作的?
- 外观设计模式 UML 类图
- 外观类和子系统的关系
- 优点
- 案例
- 外观模式在复杂业务中的应用
- 实战运用
- 1. 项目搭建与基础配置
- 2. 构建子系统组件
- 航班服务
- 酒店服务
- 旅游套餐服务
- 3. 创建外观类
- 4. 在 Controller 中使用外观类
- 小结

Pre
设计模式 - 结构型模式_外观模式
概述
外观设计模式(Facade Pattern)是一种常见的结构型设计模式,它的主要目的是简化复杂系统的使用。可以把它想象成一个“控制面板”或者“遥控器”,通过这个控制面板,用户可以轻松操作一个复杂的系统,而不需要关心系统内部是如何运作的。
举个生活中的例子 , 想象一下,你家有一台多功能的家电,比如一台智能电视,它不仅能看电视,还能上网、播放视频、控制智能家居等等。对于电视的操作,你有遥控器,可以通过一些按钮控制各种功能。
- 复杂系统:电视内部的各种硬件(显示屏、网络模块、声音系统、处理器等)和软件(操作系统、应用程序等)。
- 外观模式:遥控器,它将所有复杂的操作集中在几个按钮上,用户只需要按下遥控器上的某个按钮(比如“开机”或“返回主屏幕”),就能触发一系列复杂的操作,而不需要了解电视内部的具体工作原理。
在编程中,外观模式是如何工作的?
外观模式通过为复杂系统提供一个简洁的接口,将复杂的子系统操作封装在一个统一的外观类(Facade)中。使用者只需要与外观类交互,而不需要关心具体的实现细节。
例如,一个复杂系统涉及多个子模块,如果没有外观模式,用户(或程序)在调用时,可能需要依次与每个子模块进行交互,调用很多方法,导致代码非常复杂。通过外观模式,我们可以将这些操作封装成一个简单的方法调用,用户只需要调用外观类的方法即可。
外观模式的好处
- 简化接口:将复杂的系统封装起来,提供一个简单易懂的接口,减少了调用者的复杂度。
- 降低耦合度:外部系统不需要直接依赖复杂的子系统,只需要依赖外观类,减少了系统间的依赖。
- 提高可维护性:如果系统的内部实现发生变化,外观类的接口不变,调用者不需要修改任何代码。
- 方便扩展:新的子系统可以轻松集成,只需要修改外观类,不影响其他部分。
外观设计模式的核心思想就是 简化接口,隐藏复杂性。它提供了一个高层次的接口,简化了系统的使用,减少了客户端与复杂子系统之间的耦合度。这种模式非常适用于需要简化复杂系统、减少外部依赖的场景。
外观设计模式 UML 类图
外观设计模式的 UML 图 主要展示了外观类(Facade)如何通过统一的接口与多个子系统进行交互,并为客户端提供简化的接口

-
Client(客户端):客户端通过调用外观类(Facade)的方法来与子系统进行交互,客户端只需要关注外观类提供的简单接口,而不需要直接操作复杂的子系统。
-
Facade(外观类):外观类提供了一个统一的接口(如
operation()),将复杂的操作委托给不同的子系统。客户端通过调用外观类的方法来简化与多个子系统的交互。 -
Subsystem1, Subsystem2, Subsystem3(子系统类):这些类代表系统中的各个子模块,每个子系统类都有自己复杂的逻辑方法(如
method1()、method2()、method3()),但是客户端不直接调用它们,而是通过外观类来与之交互。
外观类和子系统的关系
- 外观类通过 组合(
subsystem1,subsystem2,subsystem3)的方式持有多个子系统的实例。 - 外观类的方法(例如
operation())在内部调用不同子系统的方法,客户端只需要调用外观类提供的简单接口,而不需要直接与多个子系统交互。
优点
- 简化接口:客户端通过外观类,避免了直接与多个复杂的子系统打交道。
- 降低耦合度:客户端与多个子系统之间的耦合减少,客户端只与外观类交互,而不需要关心子系统的具体实现。
- 增强可维护性:如果子系统的实现发生了变化,客户端无需改动,只需要修改外观类的实现即可。
案例
在构建大型系统时,业务逻辑通常分散在不同的层次之间,涉及多个功能模块,这些模块之间相互依赖,彼此交织,难以快速理解与维护。例如,一个典型的 在线旅游预订系统,其预订流程可能涉及到如下多个子系统或功能模块:
- 航班查询:根据用户输入的起点、终点和日期查询可用航班。
- 酒店预定:查询目标地点的酒店并为用户提供预定选项。
- 旅游套餐推荐:根据用户偏好推荐相关旅游套餐。
- 支付接口对接:与第三方支付接口对接完成支付。
这些环节需要在多个服务、多个方法之间传递数据与控制流。假设需求有所变动,新增了一个业务流程或修改了现有流程,往往需要在不同的层次之间修改代码,甚至可能会影响到系统的其他部分。
外观模式在复杂业务中的应用
外观模式(Facade Pattern) 是一种结构型设计模式,它提供了一个统一的接口,来访问子系统中的一组接口。外观模式通过为复杂子系统提供一个简单的接口,隐藏了系统的复杂性,使得外部调用者只需要关注简洁明了的接口,而不必关心其内部复杂的实现细节。简言之,外观模式就是在复杂的业务子系统上加一个“控制面板”(外观类),通过简单的按钮(外观类的方法)控制复杂的“机器”运转。
在一个典型的 在线旅游预订系统 中,预订业务涉及到多个子系统和服务。通过外观模式,我们可以将所有涉及的业务逻辑统一封装在一个外观类中,而上层业务只需要与该外观类交互即可,无需关心其内部的实现细节。
实战运用
以下代码简化了复杂的业务逻辑,重点体会
1. 项目搭建与基础配置
首先,创建一个 Spring Boot 项目,加入必要的依赖:
<dependencies><!-- Spring Boot Starter Web --><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><!-- Spring Boot Starter Data JPA --><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-jpa</artifactId></dependency><!-- H2 Database (for simplicity) --><dependency><groupId>com.h2database</groupId><artifactId>h2</artifactId><scope>runtime</scope></dependency>
</dependencies>
然后,我们创建相应的实体类,例如 Flight、Hotel 和 Package,并为它们创建相应的 Repository 接口:
@Entity
public class Flight {@Idprivate Long id;private String flightNumber;private String departure;private String arrival;// Getters and Setters
}@Repository
public interface FlightRepository extends JpaRepository<Flight, Long> {
}
2. 构建子系统组件
在旅游系统中,涉及到多个子系统服务,例如航班查询、酒店预定、旅游套餐推荐等。我们为这些子系统服务创建相应的组件类:
航班服务
@Service
public class FlightService {public List<Flight> findAvailableFlights(String departure, String arrival, LocalDate date) {// 实际查询数据库或调用外部航班API,此处简化逻辑System.out.println("查询航班:" + departure + " 到 " + arrival + ",日期:" + date);return List.of(new Flight(1L, "AA123", departure, arrival));}
}
酒店服务
@Service
public class HotelService {public List<Hotel> findAvailableHotels(String location, LocalDate checkInDate, LocalDate checkOutDate) {// 查询酒店信息System.out.println("查询酒店:" + location + ",入住:" + checkInDate + ",退房:" + checkOutDate);return List.of(new Hotel(1L, "Hotel California", location));}
}
旅游套餐服务
@Service
public class PackageService {public List<TourPackage> recommendPackages(String destination) {// 推荐套餐System.out.println("推荐旅游套餐:" + destination);return List.of(new TourPackage(1L, "Paris Special", destination));}
}
3. 创建外观类
接下来,我们创建一个 BookingFacade 类,将多个子系统的功能集中封装在一个外观类中:
@Service
public class BookingFacade {private final FlightService flightService;private final HotelService hotelService;private final PackageService packageService;public BookingFacade(FlightService flightService, HotelService hotelService, PackageService packageService) {this.flightService = flightService;this.hotelService = hotelService;this.packageService = packageService;}public boolean bookTravel(String departure, String arrival, LocalDate flightDate,String hotelLocation, LocalDate checkIn, LocalDate checkOut,String destination) {// 查询航班List<Flight> flights = flightService.findAvailableFlights(departure, arrival, flightDate);if (flights.isEmpty()) {return false;}// 查询酒店List<Hotel> hotels = hotelService.findAvailableHotels(hotelLocation, checkIn, checkOut);if (hotels.isEmpty()) {return false;}// 推荐旅游套餐List<TourPackage> packages = packageService.recommendPackages(destination);if (packages.isEmpty()) {return false;}return true;}
}
4. 在 Controller 中使用外观类
在 Spring Boot 的 Controller 层中,我们可以直接使用 BookingFacade 来简化业务逻辑的调用:
@RestController
@RequestMapping("/bookings")
public class BookingController {private final BookingFacade bookingFacade;public BookingController(BookingFacade bookingFacade) {this.bookingFacade = bookingFacade;}@PostMappingpublic ResponseEntity<String> bookTravel(@RequestBody TravelRequest travelRequest) {boolean success = bookingFacade.bookTravel(travelRequest.getDeparture(),travelRequest.getArrival(),travelRequest.getFlightDate(),travelRequest.getHotelLocation(),travelRequest.getCheckIn(),travelRequest.getCheckOut(),travelRequest.getDestination());if (success) {return ResponseEntity.ok("旅游预定成功");}return ResponseEntity.badRequest().body("旅游预定失败");}
}
通过以上设计,BookingController 只需要关注如何处理用户请求,而具体的业务逻辑(如航班查询、酒店预定、套餐推荐)都已经被封装在 BookingFacade 类中。无论如何修改或扩展预定业务,我们只需要在外观类中进行修改,其他地方的代码不需要做任何变动。
小结
外观模式为系统提供了统一且简洁的接口,同时隐藏了底层复杂的业务逻辑。而 Spring Boot 强大的依赖注入(DI)特性,使得各个服务的整合变得更加灵活与易于管理。
通过这种设计方式,我们能够:
- 降低代码耦合度:将复杂的子系统封装起来,暴露简单的接口,降低了不同模块之间的依赖关系。
- 提升代码可维护性:对于新增需求或业务变更,我们只需要在外观类中进行修改,而不用在多个地方重复修改。
- 增强开发效率:业务逻辑的模块化和统一化,使得开发人员能更加专注于业务实现,而不是处理复杂的交互关系。

相关文章:
Spring Boot + Facade Pattern : 通过统一接口简化多模块业务
文章目录 Pre概述在编程中,外观模式是如何工作的?外观设计模式 UML 类图外观类和子系统的关系优点案例外观模式在复杂业务中的应用实战运用1. 项目搭建与基础配置2. 构建子系统组件航班服务酒店服务旅游套餐服务 3. 创建外观类4. 在 Controller 中使用外…...
在Linux系统上安装.NET
测试系统:openKylin(开放麒麟) 1.确定系统和架构信息: 打开终端(Ctrl Alt T),输入cat /etc/os-release查看系统版本相关信息。 输入uname -m查看系统架构。确保你的系统和架构符合.NET 的要求,如果架构…...
OpenAI Operator:AI Agent 大战的号角,从 “工具” 到 “助手” 的飞跃
想尝试不同的 AI 模型?不必到处寻找!chatTools 为您集成了 o1、GPT4o、Claude 和 Gemini 等多种选择,一个平台解决您的所有 AI 需求。现在就来体验吧! 各位 AI 爱好者们,今天我们来聊聊 OpenAI 的最新力作——Operator…...
AI大模型开发原理篇-9:GPT模型的概念和基本结构
基本概念 生成式预训练模型 GPT(Generative Pre-trained Transformer)模型 是由 OpenAI 开发的基于 Transformer 架构的自然语言处理(NLP)模型,专门用于文本生成任务。它的设计理念在于通过大规模的预训练来学习语言模…...
Java Swing 基础组件详解 [论文投稿-第四届智能系统、通信与计算机网络]
大会官网:www.icisccn.net Java Swing 是一个功能强大的 GUI 工具包,提供了丰富的组件库用于构建跨平台的桌面应用程序。本文将详细讲解 Swing 的基础组件,包括其作用、使用方法以及示例代码,帮助你快速掌握 Swing 的核心知识。 一…...
vscode+WSL2(ubuntu22.04)+pytorch+conda+cuda+cudnn安装系列
最近在家过年闲的没事,于是研究起深度学习开发工具链的配置和安装,之前欲与天公试比高,尝试在win上用vscodecuda11.6vs2019的cl编译器搭建cuda c编程环境,最后惨败,沦为笑柄,痛定思痛,这次直接和…...
【letta】The Letta Platform LETTA平台
The Letta Platform LETTA平台 The Letta Platform LETTA平台开源网站2023年的论文 论文:MemGPT Towards LLMs as Operating Systems Letta enables developers to build and deploy stateful AI agents - agents that maintain memory and context across long-running conve…...
想品客老师的第九天:原型和继承
原型与继承前置看这里 原型 原型都了解了,但是不是所有对象都有对象原型 let obj1 {}console.log(obj1)let obj2 Object.create(null, {name: {value: 荷叶饭}})console.log(obj2) obj2为什么没有对象原型?obj2是完全的数据字典对象,没有…...
Time Constant | RC、RL 和 RLC 电路中的时间常数
注:本文为 “Time Constant” 相关文章合辑。 机翻,未校。 How To Find The Time Constant in RC and RL Circuits June 8, 2024 💡 Key learnings: 关键学习点: Time Constant Definition: The time constant (τ) is define…...
原码、反码、补码以及lowbit运算
原码、反码、补码以及lowbit运算 原码: 可以用来计算正数加减,正数的原码、反码、补码都一样。 第一位为符号位,符号位0为正数,1为负数(32位字符,这里用4位来举例子,后面皆是用4位来举例子,其…...
芯片AI深度实战:实战篇之vim chat
利用vim-ollama这个vim插件,可以在vim内和本地大模型聊天。 系列文章: 芯片AI深度实战:基础篇之Ollama-CSDN博客 芯片AI深度实战:基础篇之langchain-CSDN博客 芯片AI深度实战:实战篇之vim chat-CSDN博客 芯片AI深度…...
当当网近30日热销图书的数据采集与可视化分析(scrapy+openpyxl+matplotlib)
当当网近30日热销图书的数据采集与可视化分析(scrapy+openpyxl+matplotlib) 当当网近30日热销书籍官网写在前面 实验目的:实现当当网近30日热销图书的数据采集与可视化分析。 电脑系统:Windows 使用软件:Visual Studio Code Python版本:python 3.12.4 技术需求:scrapy、…...
Spring Boot 日志:项目的“行车记录仪”
一、什么是Spring Boot日志 (一)日志引入 在正式介绍日志之前,我们先来看看上篇文章中(Spring Boot 配置文件)中的验证码功能的一个代码片段: 这是一段校验用户输入的验证码是否正确的后端代码,…...
幸运数字——蓝桥杯
1.问题描述 哈沙德数是指在某个固定的进位制当中,可以被各位数字之和整除的正整数。例如 126126 是十进制下的一个哈沙德数,因为 (126)10mod(126)0;126 也是八进制下的哈沙德数,因为 (126)10(176)8,(126)10mod(176)…...
Deepseek本地部署(ollama+open-webui)
ollama 首先是安装ollama,这个非常简单 https://ollama.com/ 下载安装即可 open-webui 这个是为了提供一个ui,毕竟我们也不想在cmd和模型交互,很不方便。 第一,需要安装python3.11,必须是3.11(其他版…...
【QT】 控件 -- 显示类
🔥 目录 [TOC]( 🔥 目录) 1. 前言 2. 显示类控件2.1 Label 1、显示不同文本2、显示图片3、文本对齐、自动换行、缩进、边距4、设置伙伴 3.2 LCD Number 3.3 ProgressBar 3.4 Calendar Widget 3. 共勉 🔥 1. 前言 之前我在上一篇文章【QT】…...
冲刺蓝桥杯之速通vector!!!!!
文章目录 知识点创建增删查改 习题1习题2习题3习题4:习题5: 知识点 C的STL提供已经封装好的容器vector,也可叫做可变长的数组,vector底层就是自动扩容的顺序表,其中的增删查改已经封装好 创建 const int N30; vecto…...
指针空值——nullptr(C++11)——提升指针安全性的利器
C11引入的nullptr是对指针空值的正式支持,它提供了比传统NULL指针更加安全和明确的指针空值表示方式。在C语言中,指针操作是非常基础且常见的,而如何安全地处理指针空值,一直是开发者关注的重要问题。本文将详细讲解nullptr的引入…...
鸿蒙开发黑科技“stack叠层”替代customdialog
前一篇提到的问题,本篇博文提出了一个解决方案: arkui-x LongPressGesture触发customdialog踩坑记录-CSDN博客 前一段时间遇到的这个问题,通过排除法观察,锁定为customdialog组件有bug,极为容易挂死。不论如何调整使用方法,都还是会触发挂死。 反馈给arkui团队,说是在…...
小米CR6606,CR6608,CR6609 启用SSH和刷入OpenWRT 23.05.5
闲鱼上收了一台CR6606和一台CR6609, 一直没时间研究, 趁春节假期把这两个都刷成 OpenWRT 配置说明 CPU: MT7621AT,双核880MHz内存: NT5CC128M16JR-EKI 或 M15T2G16128A, 256MB闪存: F59L1G81MB, 128MB无线基带芯片(BB): T7905DAN无线射频芯片(RF): MT7975DN无外置F…...
SpringCloud系列教程:微服务的未来(十八)雪崩问题、服务保护方案、Sentinel快速入门
前言 在分布式系统中,雪崩效应(Avalanche Effect)是一种常见的故障现象,通常发生在系统中某个组件出现故障时,导致其他组件级联失败,最终引发整个系统的崩溃。为了有效应对雪崩效应,服务保护方…...
Web-3.0(Solidity)ERC-20
🚀 发行自己的加密货币(ERC-20 代币) 你可以使用 Solidity 编写 ERC-20 智能合约 来发行自己的加密货币,然后部署到 以太坊(Ethereum) 或 BNB/Polygon 等 EVM 兼容链。 📌 1. ERC-20 代币是什么…...
大数据相关职位介绍之一(数据分析,数据开发,数据产品经理,数据运营)
大数据相关职位介绍之一 随着大数据、人工智能(AI)和机器学习的快速发展,数据分析与管理已经成为各行各业的重要组成部分。从互联网公司到传统行业的数字转型,数据相关职位在中国日益成为推动企业创新和提升竞争力的关键力量。以…...
无人机红外热成像:应急消防的“透视眼”
无人机红外热成像:应急消防的“透视眼” 亲爱的小伙伴们,每年一到夏天,应急消防的战士们就像上紧了发条的闹钟,时刻准备应对各种灾害。炎热天气让火灾隐患“蹭蹭”往上涨,南北各地还有防洪救灾、台风、泥石流等灾害轮…...
opencv裁剪视频区域
import cv2 # 打开视频文件 video_path input.mp4 cap cv2.VideoCapture(video_path) # 获取视频的帧率、宽度和高度 fps int(cap.get(cv2.CAP_PROP_FPS)) width int(cap.get(cv2.CAP_PROP_FRAME_WIDTH)) height int(cap.get(cv2.CAP_PROP_FRAME_HEIGHT)) # 定义裁剪区…...
【狂热算法篇】探秘图论之Dijkstra 算法:穿越图的迷宫的最短路径力量(通俗易懂版)
羑悻的小杀马特.-CSDN博客羑悻的小杀马特.擅长C/C题海汇总,AI学习,c的不归之路,等方面的知识,羑悻的小杀马特.关注算法,c,c语言,青少年编程领域.https://blog.csdn.net/2401_82648291?typebbshttps://blog.csdn.net/2401_82648291?typebbshttps://blog.csdn.net/2401_8264829…...
Kafka的消息协议
引言 在学习MQTT消息协议的时候我常常思考kafka的消息协议是什么,怎么保证消息的可靠性和高性能传输的,接下来我们一同探究一下 Kafka 在不同的使用场景和组件交互中用到了多种协议,以下为你详细介绍: 内部通信协议 Kafka 使用…...
AI在自动化测试中的伦理挑战
在软件测试领域,人工智能(AI)已经不再是遥不可及的未来技术,而是正在深刻影响着测试过程的现实力量。尤其是在自动化测试领域,AI通过加速测试脚本生成、自动化缺陷检测、测试数据生成等功能,极大提升了测试…...
手撕Diffusion系列 - 第十一期 - lora微调 - 基于Stable Diffusion(代码)
手撕Diffusion系列 - 第十一期 - lora微调 - 基于Stable Diffusion(代码) 目录 手撕Diffusion系列 - 第十一期 - lora微调 - 基于Stable Diffusion(代码)Stable Diffusion 原理图Stable Diffusion的原理解释Stable Diffusion 和Di…...
新版231普通阿里滑块 自动化和逆向实现 分析
声明: 本文章中所有内容仅供学习交流使用,不用于其他任何目的,抓包内容、敏感网址、数据接口等均已做脱敏处理,严禁用于商业用途和非法用途,否则由此产生的一切后果均与作者无关! 逆向过程 补环境逆向 部分补环境 …...
