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 {
    @Id
    private 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;
    }

    @PostMapping
    public 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)特性,使得各个服务的整合变得更加灵活与易于管理。

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

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

在这里插入图片描述

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

安卓(android)实现注册界面【Android移动开发基础案例教程(第2版)黑马程序员】

一、实验目的&#xff08;如果代码有错漏&#xff0c;可查看源码&#xff09; 1.掌握LinearLayout、RelativeLayout、FrameLayout等布局的综合使用。 2.掌握ImageView、TextView、EditText、CheckBox、Button、RadioGroup、RadioButton、ListView、RecyclerView等控件在项目中的…

Prompt提示词完整案例:让chatGPT成为“书单推荐”的高手

大家好&#xff0c;我是老六哥&#xff0c;我正在共享使用AI提高工作效率的技巧。欢迎关注我&#xff0c;共同提高使用AI的技能&#xff0c;让AI成功你的个人助理。 许多人可能会跟老六哥一样&#xff0c;有过这样的体验&#xff1a;当我们遇到一个能力出众或对事物有独到见解的…

智慧园区管理平台实现智能整合提升企业运营模式与管理效率

内容概要 在当今数字化的背景下&#xff0c;智慧园区管理平台正逐渐成为企业提升运营效率和管理模式的重要工具。这个平台汇聚了多种先进技术&#xff0c;旨在通过智能整合各类资源与信息&#xff0c;帮助企业实现全面的管理创新。 智慧园区管理平台不仅仅是一个数据处理工具…

Baklib如何提升企业知识管理效率与市场竞争力的五大对比分析

内容概要 在信息化时代&#xff0c;企业在知识管理方面面临着巨大的挑战与机遇。为了有效应对这些挑战&#xff0c;“Baklib”作为一个知识中台&#xff0c;通过其高度集成的数字化平台&#xff0c;为企业提供全方位的知识管理解决方案。特别是在以下五个领域&#xff0c;它展…

c++:vector

1.使用 1.1构造函数 常见的三种构造方式&#xff1a;空构造&#xff0c;拷贝构造&#xff0c;指定元素构造 1.2iterator begin和end也分为正向和反向。 注意&#xff1a;反向迭代器可以反向遍历是因为在定义rbegin和rend函数的时候把尾地址给到了rbegin&#xff0c;而不是说改…

C++17 搜索器教程:解锁高效搜索新姿势

C17搜索器教程&#xff1a;解锁高效搜索新姿势 C17搜索器简介 在C的发展历程中&#xff0c;C17是一个重要的里程碑&#xff0c;它引入了诸多实用的新特性&#xff0c;搜索器功能便是其中之一。此功能着重对std::search算法进行了强化&#xff0c;使其支持多种搜索策略&#x…

Transformer+vit原理分析

目录 一、Transformer的核心思想 1. 自注意力机制&#xff08;Self-Attention&#xff09; 2. 多头注意力&#xff08;Multi-Head Attention&#xff09; 二、Transformer的架构 1. 整体结构 2. 编码器层&#xff08;Encoder Layer&#xff09; 3. 解码器层&#xff08;Decoder…

C语言自定义数据类型详解(二)——结构体类型(下)

书接上回&#xff0c;前面我们已经给大家介绍了如何去声明和创建一个结构体&#xff0c;如何初始化结构体变量等这些关于结构体的基础知识。下面我们将继续给大家介绍和结构体有关的知识&#xff1a; 今天的主题是&#xff1a;结构体大小的计算并简单了解一下位段的相关知识。…

【ComfyUI专栏】如何使用Git命令行安装非Manager收录节点

当前的ComfyUI的收录的自定义节点很多&#xff0c;但是有些节点属于新出来&#xff0c;或者他的应用没有那么广泛&#xff0c;Manager管理节点 有可能没有收录到&#xff0c;这时候 如果我们需要安装需要怎么办呢&#xff1f;这就涉及到我们自己安装这些节点了。例如下面的内容…

【Block总结】PKI 模块,无膨胀多尺度卷积,增强特征提取的能力|即插即用

论文信息 标题: Poly Kernel Inception Network for Remote Sensing Detection 作者: Xinhao Cai, Qiuxia Lai, Yuwei Wang, Wenguan Wang, Zeren Sun, Yazhou Yao 论文链接&#xff1a;https://arxiv.org/pdf/2403.06258 代码链接&#xff1a;https://github.com/NUST-Mac…

[OO ALV] OO ALV 基础显示

程序代码 REPORT z437_test_2025.DATA gt_spfli TYPE STANDARD TABLE OF spfli. " 内表DATA go_alv TYPE REF TO cl_gui_alv_grid. " 创建和管理ALV表格DATA gs_layout TYPE lvc_s_layo. " 存储ALV表格的布局信息*---------------------…

jQuery小游戏(二)

jQuery小游戏&#xff08;二&#xff09; 今天是新年的第二天&#xff0c;本人在这里祝大家&#xff0c;新年快乐&#xff0c;万事胜意&#x1f495; 紧接jQuery小游戏&#xff08;一&#xff09;的内容&#xff0c;我们开始继续往下咯&#x1f61c; 游戏中使用到的方法 key…

Linux的常用指令的用法

目录 Linux下基本指令 whoami ls指令&#xff1a; 文件&#xff1a; touch clear pwd cd mkdir rmdir指令 && rm 指令 man指令 cp mv cat more less head tail 管道和重定向 1. 重定向&#xff08;Redirection&#xff09; 2. 管道&#xff08;Pipes&a…

蓝桥杯之c++入门(一)【C++入门】

目录 前言5. 算术操作符5.1 算术操作符5.2 浮点数的除法5.3 负数取模5.4 数值溢出5.5 练习练习1&#xff1a;计算 ( a b ) ⋆ c (ab)^{\star}c (ab)⋆c练习2&#xff1a;带余除法练习3&#xff1a;整数个位练习4&#xff1a;整数十位练习5&#xff1a;时间转换练习6&#xff…

51单片机开发:定时器中断

目标&#xff1a;利用定时器中断&#xff0c;每隔1s开启/熄灭LED1灯。 外部中断结构图如下图所示&#xff0c;要使用定时器中断T0&#xff0c;须开启TE0、ET0。&#xff1a; 系统中断号如下图所示&#xff1a;定时器0的中断号为1。 定时器0的工作方式1原理图如下图所示&#x…

【设计测试用例自动化测试性能测试 实战篇】

&#x1f308;个人主页&#xff1a;努力学编程’ ⛅个人推荐&#xff1a; c语言从初阶到进阶 JavaEE详解 数据结构 ⚡学好数据结构&#xff0c;刷题刻不容缓&#xff1a;点击一起刷题 &#x1f319;心灵鸡汤&#xff1a;总有人要赢&#xff0c;为什么不能是我呢 设计测试用例…

指针(C语言)从0到1掌握指针,为后续学习c++打下基础

目录 一&#xff0c;指针 二&#xff0c;内存地址和指针 1&#xff0c;什么是内存地址 2&#xff0c;指针在不同系统下所占内存 三&#xff0c;指针的声明和初始化以及类型 1,指针的声明 2,指针 的初始化 1&#xff0c; 初始化方式优点及适用场景 4,指针的声明初始化类型…

利用Redis实现数据缓存

目录 1 为啥要缓存捏&#xff1f; 2 基本流程&#xff08;以查询商铺信息为例&#xff09; 3 实现数据库与缓存双写一致 3.1 内存淘汰 3.2 超时剔除&#xff08;半自动&#xff09; 3.3 主动更新&#xff08;手动&#xff09; 3.3.1 双写方案 3.3.2 读写穿透方案 3.3.…

MySQL(高级特性篇) 14 章——MySQL事务日志

事务有4种特性&#xff1a;原子性、一致性、隔离性和持久性 事务的隔离性由锁机制实现事务的原子性、一致性和持久性由事务的redo日志和undo日志来保证&#xff08;1&#xff09;REDO LOG称为重做日志&#xff0c;用来保证事务的持久性&#xff08;2&#xff09;UNDO LOG称为回…

S4 HANA明确税金本币和外币之间转换汇率确定(OBC8)

本文主要介绍在S4 HANA OP中明确明确税金本币和外币之间转换汇率确定(OBC8)相关设置。具体请参照如下内容&#xff1a; 明确税金本币和外币之间转换汇率确定(OBC8) 以上配置&#xff0c;我们可以根据不同公司代码所配置的使用不同的汇率来对税金外币和本币之间进行换算。来针对…