Spring Boot + Facade Pattern : 通过统一接口简化多模块业务

文章目录

  • Pre
  • 概述
  • 在编程中,外观模式是如何工作的?
  • 外观设计模式 UML 类图
  • 外观类和子系统的关系
  • 优点
  • 案例
    • 外观模式在复杂业务中的应用
    • 实战运用
      • 1. 项目搭建与基础配置
      • 2. 构建子系统组件
        • 航班服务
        • 酒店服务
        • 旅游套餐服务
      • 3. 创建外观类
      • 4. 在 Controller 中使用外观类
  • 小结

在这里插入图片描述


Pre

设计模式 - 结构型模式_外观模式

概述

外观设计模式(Facade Pattern)是一种常见的结构型设计模式,它的主要目的是简化复杂系统的使用。可以把它想象成一个“控制面板”或者“遥控器”,通过这个控制面板,用户可以轻松操作一个复杂的系统,而不需要关心系统内部是如何运作的。

举个生活中的例子 , 想象一下,你家有一台多功能的家电,比如一台智能电视,它不仅能看电视,还能上网、播放视频、控制智能家居等等。对于电视的操作,你有遥控器,可以通过一些按钮控制各种功能。

  • 复杂系统:电视内部的各种硬件(显示屏、网络模块、声音系统、处理器等)和软件(操作系统、应用程序等)。
  • 外观模式:遥控器,它将所有复杂的操作集中在几个按钮上,用户只需要按下遥控器上的某个按钮(比如“开机”或“返回主屏幕”),就能触发一系列复杂的操作,而不需要了解电视内部的具体工作原理。

在编程中,外观模式是如何工作的?

外观模式通过为复杂系统提供一个简洁的接口,将复杂的子系统操作封装在一个统一的外观类(Facade)中。使用者只需要与外观类交互,而不需要关心具体的实现细节。

例如,一个复杂系统涉及多个子模块,如果没有外观模式,用户(或程序)在调用时,可能需要依次与每个子模块进行交互,调用很多方法,导致代码非常复杂。通过外观模式,我们可以将这些操作封装成一个简单的方法调用,用户只需要调用外观类的方法即可。

外观模式的好处

  1. 简化接口:将复杂的系统封装起来,提供一个简单易懂的接口,减少了调用者的复杂度。
  2. 降低耦合度:外部系统不需要直接依赖复杂的子系统,只需要依赖外观类,减少了系统间的依赖。
  3. 提高可维护性:如果系统的内部实现发生变化,外观类的接口不变,调用者不需要修改任何代码。
  4. 方便扩展:新的子系统可以轻松集成,只需要修改外观类,不影响其他部分。

外观设计模式的核心思想就是 简化接口,隐藏复杂性。它提供了一个高层次的接口,简化了系统的使用,减少了客户端与复杂子系统之间的耦合度。这种模式非常适用于需要简化复杂系统、减少外部依赖的场景。


外观设计模式 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>

然后,我们创建相应的实体类,例如 FlightHotelPackage,并为它们创建相应的 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)特性,使得各个服务的整合变得更加灵活与易于管理。

通过这种设计方式,我们能够:

  • 降低代码耦合度:将复杂的子系统封装起来,暴露简单的接口,降低了不同模块之间的依赖关系。
  • 提升代码可维护性:对于新增需求或业务变更,我们只需要在外观类中进行修改,而不用在多个地方重复修改。
  • 增强开发效率:业务逻辑的模块化和统一化,使得开发人员能更加专注于业务实现,而不是处理复杂的交互关系。

在这里插入图片描述

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

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

八、Spring Boot 日志详解

目录 一、日志的用途 二、日志使用 2.1 打印日志 2.1.1 在程序中获取日志对象 2.1.2 使用日志对象打印日志 2.2、日志框架介绍 2.2.1 门面模式(外观模式) 2.2.2 门面模式的实现 2.2.3 SLF4J 框架介绍 2.3 日志格式的说明 2.4 日志级别 2.4.1 日志级别的分类 2.4.2…

创建前端项目的方法

目录 一、创建前端项目的方法 1.前提&#xff1a;安装Vue CLI 2.方式一&#xff1a;vue create项目名称 3.方式二&#xff1a;vue ui 二、Vue项目结构 三、修改Vue项目端口号的方法 一、创建前端项目的方法 1.前提&#xff1a;安装Vue CLI npm i vue/cli -g 2.方式一&…

(leetcode 213 打家劫舍ii)

代码随想录&#xff1a; 将一个线性数组换成两个线性数组&#xff08;去掉头&#xff0c;去掉尾&#xff09; 分别求两个线性数组的最大值 最后求这两个数组的最大值 代码随想录视频 #include<iostream> #include<vector> #include<algorithm> //nums:2,…

【Python】第七弹---Python基础进阶:深入字典操作与文件处理技巧

✨个人主页&#xff1a; 熬夜学编程的小林 &#x1f497;系列专栏&#xff1a; 【C语言详解】 【数据结构详解】【C详解】【Linux系统编程】【MySQL】【Python】 目录 1、字典 1.1、字典是什么 1.2、创建字典 1.3、查找 key 1.4、新增/修改元素 1.5、删除元素 1.6、遍历…

本地部署DeepSeek开源多模态大模型Janus-Pro-7B实操

本地部署DeepSeek开源多模态大模型Janus-Pro-7B实操 Janus-Pro-7B介绍 Janus-Pro-7B 是由 DeepSeek 开发的多模态 AI 模型&#xff0c;它在理解和生成方面取得了显著的进步。这意味着它不仅可以处理文本&#xff0c;还可以处理图像等其他模态的信息。 模型主要特点:Permalink…

BW AO/工作簿权限配置

场景&#xff1a; 按事业部配置工作簿权限&#xff1b; 1、创建用户 事务码&#xff1a;SU01&#xff0c;用户主数据的维护&#xff0c;可以创建、修改、删除、锁定、解锁、修改密码等 用户设置详情页 2、创建权限角色 用户的权限菜单是通过权限角色分配来实现的 2.1、自定…

jstat命令详解

jstat 用于监视虚拟机运行时状态信息的命令&#xff0c;它可以显示出虚拟机进程中的类装载、内存、垃圾收集、JIT 编译等运行数据。 命令的使用格式如下。 jstat [option] LVMID [interval] [count]各个参数详解&#xff1a; option&#xff1a;操作参数LVMID&#xff1a;本…

3.Spring-事务

一、隔离级别&#xff1a; 脏读&#xff1a; 一个事务访问到另外一个事务未提交的数据。 不可重复读&#xff1a; 事务内多次查询相同条件返回的结果不同。 幻读&#xff1a; 一个事务在前后两次查询同一个范围的时候&#xff0c;后一次查询看到了前一次查询没有看到的行。 二…

MYSQL--一条SQL执行的流程,分析MYSQL的架构

文章目录 第一步建立连接第二部解析 SQL第三步执行 sql预处理优化阶段执行阶段索引下推 执行一条select 语句中间会发生什么&#xff1f; 这个是对 mysql 架构的深入理解。 select * from product where id 1;对于mysql的架构分层: mysql 架构分成了 Server 层和存储引擎层&a…

ReentrantReadWriteLock源码分析

文章目录 概述一、状态位设计二、读锁三、锁降级机制四、写锁总结 概述 ReentrantReadWriteLock&#xff08;读写锁&#xff09;是对于ReentranLock&#xff08;可重入锁&#xff09;的一种改进&#xff0c;在可重入锁的基础上&#xff0c;进行了读写分离。适用于读多写少的场景…

51单片机开发:温度传感器

温度传感器DS18B20&#xff1a; 初始化时序图如下图所示&#xff1a; u8 ds18b20_init(void){ds18b20_reset();return ds18b20_check(); }void ds18b20_reset(void){DS18B20_PORT 0;delay_10us(75);DS18B20_PORT 1;delay_10us(2); }u8 ds18b20_check(void){u8 time_temp0;wh…

vue2项目(一)

项目介绍 电商前台项目 技术架构&#xff1a;vuewebpackvuexvue-routeraxiosless.. 封装通用组件登录注册token购物车支付项目性能优化 一、项目初始化 使用vue create projrct_vue2在命令行窗口创建项目 1.1、脚手架目录介绍 ├── node_modules:放置项目的依赖 ├──…

labelme_json_to_dataset ValueError: path is on mount ‘D:‘,start on C

这是你的labelme运行时label照片的盘和保存目的地址的盘不同都值得报错 labelme_json_to_dataset ValueError: path is on mount D:,start on C 只需要放一个盘但可以不放一个目录

物联网 STM32【源代码形式-使用以太网】连接OneNet IOT从云产品开发到底层MQTT实现,APP控制 【保姆级零基础搭建】

物联网&#xff08;IoT&#xff09;‌是指通过各种信息传感器、射频识别技术、全球定位系统、红外感应器等装置与技术&#xff0c;实时采集并连接任何需要监控、连接、互动的物体或过程&#xff0c;实现对物品和过程的智能化感知、识别和管理。物联网的核心功能包括数据采集与监…

无心剑七绝《深度求索》

七绝深度求索 深研妙理定乾坤 度世玄机启智门 求路千难兼万险 索萦华夏自为尊 2025年2月1日 平水韵十三元平韵 无心剑七绝《深度求索》以平水韵十三元平韵写成&#xff0c;意境深远&#xff0c;气势磅礴。诗中“深研妙理定乾坤”开篇点题&#xff0c;展现出对深奥道理的钻研与探…

Hot100之普通数组

53最大子数组和 题目 思路解析 我们用一个dp数组来收集我们从左往右&#xff0c;加起来的最大的和 也就是我们的节点不是负数&#xff0c;那我们直接收集就好了 如果是负数&#xff0c;我们就用Max&#xff08;&#xff09;比较是这个节点大还是当前节点大&#xff08;这个情…

如何利用天赋实现最大化的价值输出-补

原文&#xff1a; https://blog.csdn.net/ZhangRelay/article/details/145408621 ​​​​​​如何利用天赋实现最大化的价值输出-CSDN博客 如何利用天赋实现最大化的价值输出-CSDN博客 引用视频差异 第一段视频目标明确&#xff0c;建议也非常明确。 录制视频的人是主动性…

新能源算力战争:为什么AI大模型需要绿色数据中心?

新能源算力战争:为什么AI大模型需要绿色数据中心? 近年来,人工智能(AI)大模型的爆发式增长正在重塑全球科技产业的格局。以GPT-4、Gemini、Llama等为代表的千亿参数级模型,不仅需要海量数据训练,更依赖庞大的算力支撑。然而,这种算力的背后隐藏着一个日益严峻的挑战——…

Spring Boot 中的事件发布与监听:深入理解 ApplicationEventPublisher(附Demo)

目录 前言1. 基本知识2. Demo3. 实战代码 前言 &#x1f91f; 找工作&#xff0c;来万码优才&#xff1a;&#x1f449; #小程序://万码优才/r6rqmzDaXpYkJZF 基本的Java知识推荐阅读&#xff1a; java框架 零基础从入门到精通的学习路线 附开源项目面经等&#xff08;超全&am…

unity学习24:场景scene相关生成,加载,卸载,加载进度,异步加载场景等

目录 1 场景数量 SceneManager.sceneCount 2 直接代码生成新场景 SceneManager.CreateScene 3 场景的加载 3.1 用代码加载场景&#xff0c;仍然build setting里先加入配置 3.2 卸载场景 SceneManager.UnloadSceneAsync(); 3.3 同步加载场景 SceneManager.LoadScene 3.3.…