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

解锁Spring Boot中的设计模式—04.桥接模式:探索【桥接模式】的奥秘与应用实践!

桥接模式

桥接模式也称为桥梁模式、接口模式或者柄体(Handle and Body)模式,是将抽象部分与他的具体实现部分分离,使它们都可以独立地变化,通过组合的方式建立两个类之间的联系,而不是继承。

桥接模式是一种结构型设计模式,旨在将抽象部分与实现部分分离,使它们可以独立地变化。这种模式通过使用组合而不是继承的方式,可以更灵活地组织和管理代码。

结构:

  • 抽象部分(Abstraction):定义抽象类或接口,并维护一个指向实现部分的引用。
  • 扩充抽象类(Refined Abstraction):扩展抽象部分,可以添加更多的功能。
  • 实现部分(Implementor):定义实现类接口,供抽象部分调用。
  • 具体实现类(Concrete Implementor):实现实现部分的接口,提供具体的功能实现

优点:

  1. 解耦合:桥接模式能够将抽象部分和实现部分分离,使它们可以独立地进行变化。这种解耦合使得系统更加灵活和可维护。
  2. 扩展性:由于桥接模式采用了组合的方式而不是继承,因此更容易扩展和变化。新的抽象部分和实现部分可以独立地添加和修改,而不会对现有的代码产生影响。
  3. 隐藏实现细节:桥接模式可以隐藏实现的细节,使客户端代码只关注于抽象部分,而不需要关心具体的实现细节。这种隐藏可以减少系统中的耦合度,提高代码的可维护性和可理解性。
  4. 适应变化:桥接模式使得系统更加灵活和适应变化。通过抽象部分和实现部分的分离,系统可以更容易地应对需求的变化和新的功能的添加。

缺点:

  1. 增加复杂性:桥接模式引入了抽象部分和实现部分之间的桥梁,可能会增加系统的复杂性。特别是对于简单的系统,使用桥接模式可能会显得过于复杂。
  2. 理解成本:由于桥接模式涉及到多个类和接口之间的关系,可能会增加新成员对系统的理解成本。需要仔细地理解抽象部分和实现部分之间的关系,以及桥接模式的设计思想。
  3. 过度设计:在某些情况下,使用桥接模式可能会导致过度设计的问题。如果系统的抽象部分和实现部分之间的关系比较简单,使用桥接模式可能会显得不够自然和合适。
  4. 设计复用性:虽然桥接模式提高了系统的灵活性和扩展性,但如果不恰当地使用,可能会导致设计复用性下降。过度使用桥接模式可能会导致代码结构的过度抽象,使得代码变得难以理解和维护。

注意事项

  • 桥接模式适用于系统中多个维度的变化。
  • 避免过度设计,只有当两个维度中的一个或两个具有多个实现时才考虑使用桥接模式。

适用场景

  • 系统有多个维度同时变化,且不希望使用多层继承。
  • 想要在抽象和实现之间建立一个稳定的联系,但又不希望二者紧密耦合。

1.案例1-发送通知

需求

假设我们正在开发一个电商平台,该平台需要发送不同类型的通知给用户,例如电子邮件通知、短信通知、App推送通知等。同时,用户可能也有不同的偏好和设备,例如有些用户更喜欢通过邮件接收通知,而另一些用户则更倾向于使用手机App接收通知。

实现思路

  1. 通知接口(Notification):定义了发送通知的方法。
  2. 具体通知类(ConcreteNotification):实现了通知接口的具体通知类型,如邮件通知、短信通知、App推送通知等。
  3. 用户偏好(UserPreference):定义了用户的通知偏好,包含具体通知类,例如用户更喜欢接收邮件通知还是App推送通知。
  4. 用户类(User)包含用户的信息和偏好设置
  5. 通知服务类(NotificationService):负责根据用户的偏好选择合适的通知方式进行发送。(包含用户信息
Notification
+sendNotification(message)
EmailNotification
+sendNotification(message)
SMSNotification
+sendNotification(message)
AppNotification
+sendNotification(message)
UserPreference
+getNotification()
User
-preference: UserPreference
+receiveNotification(message)
NotificationService
+sendNotificationToUser(user, message)

在这里插入图片描述

1.1.通知接口
/*** 通知接口* @author 13723* @version 1.0* 2024/2/7 10:17*/
public interface Notification {/*** 通知* @param message 通知消息*/void notify(String message);
}
1.1.2.具体通知类-APP
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.lang.invoke.MethodHandles;/*** APP通知类* @author 13723* @version 1.0* 2024/2/7 10:19*/
public class APPNotification implements Notification{private static final Logger logger = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass());/*** APP通知* @param message 通知消息*/@Overridepublic void notify(String message) {logger.error("【APP通知】: {}", message);}
}
1.1.3.具体通知类-短信
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.lang.invoke.MethodHandles;/*** 邮箱通知类* @author 13723* @version 1.0* 2024/2/7 10:21*/
public class EMailNotification implements Notification{private static final Logger logger = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass());/*** 邮箱通知* @param message 通知消息*/@Overridepublic void notify(String message) {logger.error("【邮件通知】: {}", message);}
}
1.1.4.具体通知类-邮箱
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.lang.invoke.MethodHandles;/*** 邮箱通知类* @author 13723* @version 1.0* 2024/2/7 10:21*/
public class EMailNotification implements Notification{private static final Logger logger = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass());/*** 邮箱通知* @param message 通知消息*/@Overridepublic void notify(String message) {logger.error("【邮件通知】: {}", message);}
}
1.1.5.用户偏好类
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.lang.invoke.MethodHandles;/*** 用户偏好类* @author 13723* @version 1.0* 2024/2/7 10:23*/
public class UserPreference {private static final Logger logger = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass());/*** 此处引入通知接口,实现桥接模式,将通知接口和用户偏好类解耦*/private Notification notification;/*** 用户偏好* @param notification 通知*/public UserPreference(Notification notification) {this.notification = notification;}public Notification getNotification() {return notification;}
}
1.1.6.用户类
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.lang.invoke.MethodHandles;/*** 用户类* @author 13723* @version 1.0* 2024/2/7 10:26*/
public class User {private static final Logger logger = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass());/*** 用户名称*/private String name;/*** 用户偏好*/private UserPreference userPreference;public User(String name, UserPreference userPreference) {this.name = name;this.userPreference = userPreference;}protected void receiveNotification(String message) {message = name + ":" + message;userPreference.getNotification().notify(message);}}
1.1.7.服务通知类
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.lang.invoke.MethodHandles;/*** @author 13723* @version 1.0* 2024/2/7 10:37*/
public class NotificationService {private static final Logger logger = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass());/*** 发送通知* @param user 用户,用户里面已经设置好偏好通知了,偏好通知里面已经设置好具体的通知方式了* @param message 通知消息*/public void sendNotification(User user, String message) {user.receiveNotification(message);}
}
1.1.8.测试类
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.lang.invoke.MethodHandles;/*** 测试 桥梁模式-通知用户* @author 13723* @version 1.0* 2024/2/7 10:42*/
public class NotificationTest {private static final Logger logger = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass());@Test@DisplayName("测试通知用户")public void testNotification() {// 设置通知方式APPNotification appNotification = new APPNotification();SMSNotification smsNotification = new SMSNotification();// 设置用户偏好UserPreference zs = new UserPreference(appNotification);UserPreference ls = new UserPreference(smsNotification);// 设置用户User user1 = new User("张三", zs);User user2 = new User("李四", ls);// 通知服务NotificationService notificationService = new NotificationService();notificationService.sendNotification(user1, "你好,你的账号被人盗走了!请联系客户找回,85852555!");notificationService.sendNotification(user2, "你好,你的账号被人盗走了!请联系客户找回,85852555!");}
}

在这里插入图片描述

2.Spring代码-JdbcTemplate

2.1.案例

@SpringBootTest
public class BridgeTest {private static final Logger logger = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass());@Test@DisplayName("测试template")public void test(){DriverManagerDataSource dataSource = new DriverManagerDataSource();dataSource.setDriverClassName("org.postgresql.Driver");dataSource.setUrl("jdbc:postgresql://192.168.1.56/postgres?currentSchema=gwstd");dataSource.setUsername("postgres");dataSource.setPassword("152564.lmy");JdbcTemplate jdbcTemplate = new JdbcTemplate();jdbcTemplate.setDataSource(dataSource);String sql = "select * from t_dec_order_head limit 1";List<Map<String, Object>> maps = jdbcTemplate.queryForList(sql);for (Map<String, Object> map : maps) {logger.error("result:{}",map);}}
}

在这里插入图片描述

JdbcTemplate 使用了桥接模式来实现数据库操作的抽象和实现的解耦合。这种模式使得应用程序能够专注于高级的业务逻辑,而不必关心底层数据库访问的细节。

JdbcTemplate 使用了以下几个关键角色:

  1. 抽象部分(Abstraction)
    • JdbcTemplate 中,抽象部分代表了对数据库操作的抽象接口,例如 JdbcTemplate 类本身以及它的一些方法,如 query()update() 等。
    • 这些方法定义了客户端与数据库交互的高级操作,比如查询数据、更新数据等。
  2. 扩充抽象类(Refined Abstraction)
    • 在 JdbcTemplate 中,扩充抽象部分是对抽象部分的扩展,可以添加更多的功能或者调整现有的功能。
    • 例如,你可以创建自定义的 JdbcTemplate 子类,通过添加新的方法或者重写现有方法来实现更具体的数据库操作。
  3. 实现部分(Implementor)
    • JdbcTemplate 中,实现部分代表了对底层数据库访问的实现,例如 DataSource 接口和各种数据库驱动实现。
    • 这些实现提供了底层的数据库连接和操作功能,但不暴露给应用程序直接使用。
  4. 具体实现类(Concrete Implementor)
    • 具体实现类是实现部分的具体实现,比如 DriverManagerDataSourceC3P0DataSource 等。
    • 它们提供了具体的数据库连接池实现、连接配置等功能。
// 在创建JDBC的模板类时,需要传入数据源,这样JDBC的模板类才知道连接哪个数据库

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

相关文章:

解锁Spring Boot中的设计模式—04.桥接模式:探索【桥接模式】的奥秘与应用实践!

桥接模式 桥接模式也称为桥梁模式、接口模式或者柄体&#xff08;Handle and Body&#xff09;模式&#xff0c;是将抽象部分与他的具体实现部分分离&#xff0c;使它们都可以独立地变化&#xff0c;通过组合的方式建立两个类之间的联系&#xff0c;而不是继承。 桥接模式是一种…...

[talib][python]ta-lib所有whl文件下载地址汇总

TA-Lib-0.4.28-cp312-cp312-win-amd64.whl下载地址&#xff1a;https://download.csdn.net/download/FL1623863129/88589956 ta-lib-0.4.25-cp311-cp311-win-amd64.whl下载地址&#xff1a;https://download.csdn.net/download/FL1623863129/88265329 TA-Lib-0.4.24-cp310-cp31…...

【开源】JAVA+Vue.js实现农村物流配送系统

目录 一、摘要1.1 项目介绍1.2 项目录屏 二、功能模块2.1 系统登录、注册界面2.2 系统功能2.2.1 快递信息管理&#xff1a;2.2.2 位置信息管理&#xff1a;2.2.3 配送人员分配&#xff1a;2.2.4 路线规划&#xff1a;2.2.5 个人中心&#xff1a;2.2.6 退换快递处理&#xff1a;…...

锁相放大器,数字锁相放大器.C和python版的源代码

数字锁相放大器. 锁相放大器, 它是一种可以从高噪声环境中提取出特定频率信号的放大器&#xff0c;工作原理主要是利用正弦函数的正交性进行信号的相位检测和幅值测量。如果你对锁相放大器感兴趣&#xff0c;我可以给你更详细的解释。 数字锁相放大器是利用软件算法来实现提取…...

(02)Hive SQL编译成MapReduce任务的过程

目录 一、架构及组件介绍 1.1 Hive底层架构 1.2 Hive组件 1.3 Hive与Hadoop交互过程 二、Hive SQL 编译成MR任务的流程 2.1 HQL转换为MR源码整体流程介绍 2.2 程序入口—CliDriver 2.3 HQL编译成MR任务的详细过程—Driver 2.3.1 将HQL语句转换成AST抽象语法树 词法、语…...

【C++初阶】值得一刷的字符串string相关oj题

&#x1f466;个人主页&#xff1a;Weraphael ✍&#x1f3fb;作者简介&#xff1a;目前学习C和算法 ✈️专栏&#xff1a;C航路 &#x1f40b; 希望大家多多支持&#xff0c;咱一起进步&#xff01;&#x1f601; 如果文章对你有帮助的话 欢迎 评论&#x1f4ac; 点赞&#x1…...

《Go 简易速速上手小册》第10章:微服务与云原生应用(2024 最新版)

文章目录 10.1 构建微服务架构 - 探索 Go 语言的微观世界10.1.1 基础知识讲解10.1.2 重点案例&#xff1a;订单处理系统订单服务测试服务 10.1.3 拓展案例 1&#xff1a;用户认证服务安装所需的包实现用户模型和存储实现 JWT 生成和验证实现认证服务测试服务 10.1.4 拓展案例 2…...

代码随想录算法训练营第34天| Leetcode 860.柠檬水找零、406.根据身高重建队列、452. 用最少数量的箭引爆气球

文章目录 Leetcode 860.柠檬水找零Leetcode 406.根据身高重建队列Leetcode 452. 用最少数量的箭引爆气球 Leetcode 860.柠檬水找零 题目链接&#xff1a;Leetcode 860.柠檬水找零 题目描述&#xff1a; 在柠檬水摊上&#xff0c;每一杯柠檬水的售价为 5 美元。顾客排队购买你的…...

数据结构~二叉树(基础知识)

上一篇博客我们对树有了初步了解与学习&#xff0c;这篇我将初步学习二叉树&#xff01;&#xff01;&#xff08;新年快乐&#xff01;&#xff09; 目录 二叉树 1、定义&#xff1a; 2、特点&#xff1a; 3、基本形态&#xff1a; 4、二叉树的种类&#xff1a; &…...

AI大模型学习笔记之四:生成式人工智能(AIGC)是如何工作的?

OpenAI 发布 ChatGPT 已经1年多了&#xff0c;生成式人工智能&#xff08;AIGC&#xff09;也已经广为人知&#xff0c;我们常常津津乐道于 ChatGPT 和 Claude 这样的人工智能系统能够神奇地生成文本与我们对话&#xff0c;并且能够记忆上下文情境。 Midjunery和DALLE 这样的AI…...

bat脚本 创建计划任务 一分钟设置ntp同步周期为60s

要在Windows中使用批处理脚本&#xff08;.bat&#xff09;创建一个计划任务来每分钟同步一次NTP时间&#xff0c;你可以使用schtasks命令来创建计划任务。下面是一个示例脚本&#xff0c;展示了如何创建这样一个计划任务&#xff1a; echo off set "taskNameSyncNTP"…...

python数据分析numpy基础之mean用法和示例

1 python数据分析numpy基础之mean用法和示例 python的numpy库的mean()函数&#xff0c;用于计算沿指定轴(一个轴或多个轴)的算术平均值。 用法 numpy.mean(a, axisNone, dtypeNone, outNone, keepdims<no value>, *, where<no value>)描述 返回数组元素的平均值…...

微服务学习 | Springboot整合Dubbo+Nacos实现RPC调用

&#x1f3f7;️个人主页&#xff1a;鼠鼠我捏&#xff0c;要死了捏的主页 &#x1f3f7;️系列专栏&#xff1a;Golang全栈-专栏 &#x1f3f7;️个人学习笔记&#xff0c;若有缺误&#xff0c;欢迎评论区指正 前些天发现了一个巨牛的人工智能学习网站&#xff0c;通俗易懂&…...

只允许访问固定网址,如何让电脑只能上指定的网站

在企业管理中&#xff0c;确保员工在工作时能够专注于指定的任务和资源至关重要。为了实现这一目标&#xff0c;许多企业选择限制员工电脑的访问权限&#xff0c;只允许他们访问固定的网址或网站。 这种策略不仅有助于提高工作效率&#xff0c;还能减少因不当上网行为带来的安全…...

作业帮 x TiDB丨多元化海量数据业务的支撑

导读 作业帮是一家成立于 2015 年的在线教育品牌&#xff0c;致力于用科技手段助力教育普惠。经过近十年的积累&#xff0c;作业帮运用人工智能、大数据等技术&#xff0c;为学生、老师、家长提供学习、教育解决方案&#xff0c;智能硬件产品等。随着公司产品和业务场景越来越…...

文生图提示词:天气条件

天气和气候 --天气条件 Weather Conditions 涵盖了从基本的天气类型到复杂的气象现象&#xff0c;为描述不同的天气和气候条件提供了丰富的词汇。 Sunny 晴朗 Cloudy 多云 Overcast 阴天 Partly Cloudy 局部多云 Clear 清晰 Foggy 雾 Misty 薄雾 Hazy 朦胧 Rainy 下雨 Showers …...

【nginx实践连载-3】发布VSTO应用

要使用 Nginx 发布 VSTO 应用程序&#xff0c;需要将 ClickOnce 发布文件夹部署到 Nginx 服务器上。以下是一些步骤&#xff1a; 将 ClickOnce 发布文件夹复制到 Nginx 服务器上。确认 Nginx 配置文件中有一个指向 ClickOnce 发布文件夹的位置块。确保Nginx 配置文件中启用了 …...

【前端工程化面试题】使用 webpack 来优化前端性能/ webpack的功能

这个题目实际上就是来回答 webpack 是干啥的&#xff0c;你对webpack的理解&#xff0c;都是一个问题。 &#xff08;1&#xff09;对 webpack 的理解 webpack 为啥提出 webpack 是啥 webpack 的主要功能 前端开发通常是基于模块化的&#xff0c;为了提高开发效率&#xff0…...

思迈特再获国家权威认证:代码自主率98.78%

日前&#xff0c;思迈特软件自主研发的商业智能与数据分析软件&#xff08;Smartbi Insight&#xff09;通过中国赛宝实验室&#xff08;工业和信息化部电子第五研究所&#xff09;代码扫描测试&#xff0c;Smartbi Insight V11版本扫描测得代码自主率为98.78%的好成绩&#xf…...

JavaScript排序

直接看代码 <table border"1" cellspacing"0"><thead class"tou"><tr><td>选择按钮</td><td>汽车编号</td><td>汽车图片</td><td>汽车系列名称</td><td>汽车能源</…...

linux之kylin系统nginx的安装

一、nginx的作用 1.可做高性能的web服务器 直接处理静态资源&#xff08;HTML/CSS/图片等&#xff09;&#xff0c;响应速度远超传统服务器类似apache支持高并发连接 2.反向代理服务器 隐藏后端服务器IP地址&#xff0c;提高安全性 3.负载均衡服务器 支持多种策略分发流量…...

Redis相关知识总结(缓存雪崩,缓存穿透,缓存击穿,Redis实现分布式锁,如何保持数据库和缓存一致)

文章目录 1.什么是Redis&#xff1f;2.为什么要使用redis作为mysql的缓存&#xff1f;3.什么是缓存雪崩、缓存穿透、缓存击穿&#xff1f;3.1缓存雪崩3.1.1 大量缓存同时过期3.1.2 Redis宕机 3.2 缓存击穿3.3 缓存穿透3.4 总结 4. 数据库和缓存如何保持一致性5. Redis实现分布式…...

条件运算符

C中的三目运算符&#xff08;也称条件运算符&#xff0c;英文&#xff1a;ternary operator&#xff09;是一种简洁的条件选择语句&#xff0c;语法如下&#xff1a; 条件表达式 ? 表达式1 : 表达式2• 如果“条件表达式”为true&#xff0c;则整个表达式的结果为“表达式1”…...

Nginx server_name 配置说明

Nginx 是一个高性能的反向代理和负载均衡服务器&#xff0c;其核心配置之一是 server 块中的 server_name 指令。server_name 决定了 Nginx 如何根据客户端请求的 Host 头匹配对应的虚拟主机&#xff08;Virtual Host&#xff09;。 1. 简介 Nginx 使用 server_name 指令来确定…...

Matlab | matlab常用命令总结

常用命令 一、 基础操作与环境二、 矩阵与数组操作(核心)三、 绘图与可视化四、 编程与控制流五、 符号计算 (Symbolic Math Toolbox)六、 文件与数据 I/O七、 常用函数类别重要提示这是一份 MATLAB 常用命令和功能的总结,涵盖了基础操作、矩阵运算、绘图、编程和文件处理等…...

什么?连接服务器也能可视化显示界面?:基于X11 Forwarding + CentOS + MobaXterm实战指南

文章目录 什么是X11?环境准备实战步骤1️⃣ 服务器端配置(CentOS)2️⃣ 客户端配置(MobaXterm)3️⃣ 验证X11 Forwarding4️⃣ 运行自定义GUI程序(Python示例)5️⃣ 成功效果![在这里插入图片描述](https://i-blog.csdnimg.cn/direct/55aefaea8a9f477e86d065227851fe3d.pn…...

Java多线程实现之Thread类深度解析

Java多线程实现之Thread类深度解析 一、多线程基础概念1.1 什么是线程1.2 多线程的优势1.3 Java多线程模型 二、Thread类的基本结构与构造函数2.1 Thread类的继承关系2.2 构造函数 三、创建和启动线程3.1 继承Thread类创建线程3.2 实现Runnable接口创建线程 四、Thread类的核心…...

【数据分析】R版IntelliGenes用于生物标志物发现的可解释机器学习

禁止商业或二改转载&#xff0c;仅供自学使用&#xff0c;侵权必究&#xff0c;如需截取部分内容请后台联系作者! 文章目录 介绍流程步骤1. 输入数据2. 特征选择3. 模型训练4. I-Genes 评分计算5. 输出结果 IntelliGenesR 安装包1. 特征选择2. 模型训练和评估3. I-Genes 评分计…...

服务器--宝塔命令

一、宝塔面板安装命令 ⚠️ 必须使用 root 用户 或 sudo 权限执行&#xff01; sudo su - 1. CentOS 系统&#xff1a; yum install -y wget && wget -O install.sh http://download.bt.cn/install/install_6.0.sh && sh install.sh2. Ubuntu / Debian 系统…...

libfmt: 现代C++的格式化工具库介绍与酷炫功能

libfmt: 现代C的格式化工具库介绍与酷炫功能 libfmt 是一个开源的C格式化库&#xff0c;提供了高效、安全的文本格式化功能&#xff0c;是C20中引入的std::format的基础实现。它比传统的printf和iostream更安全、更灵活、性能更好。 基本介绍 主要特点 类型安全&#xff1a…...