解锁Spring Boot中的设计模式—04.桥接模式:探索【桥接模式】的奥秘与应用实践!
桥接模式
桥接模式也称为桥梁模式、接口模式或者柄体(Handle and Body)模式,是将抽象部分与他的具体实现部分分离,使它们都可以独立地变化,通过组合的方式建立两个类之间的联系,而不是继承。
桥接模式是一种结构型设计模式,旨在将抽象部分与实现部分分离,使它们可以独立地变化。这种模式通过使用组合而不是继承的方式,可以更灵活地组织和管理代码。
结构:
- 抽象部分(Abstraction):定义抽象类或接口,并维护一个指向实现部分的引用。
- 扩充抽象类(Refined Abstraction):扩展抽象部分,可以添加更多的功能。
- 实现部分(Implementor):定义实现类接口,供抽象部分调用。
- 具体实现类(Concrete Implementor):实现实现部分的接口,提供具体的功能实现
优点:
- 解耦合:桥接模式能够将抽象部分和实现部分分离,使它们可以独立地进行变化。这种解耦合使得系统更加灵活和可维护。
- 扩展性:由于桥接模式采用了组合的方式而不是继承,因此更容易扩展和变化。新的抽象部分和实现部分可以独立地添加和修改,而不会对现有的代码产生影响。
- 隐藏实现细节:桥接模式可以隐藏实现的细节,使客户端代码只关注于抽象部分,而不需要关心具体的实现细节。这种隐藏可以减少系统中的耦合度,提高代码的可维护性和可理解性。
- 适应变化:桥接模式使得系统更加灵活和适应变化。通过抽象部分和实现部分的分离,系统可以更容易地应对需求的变化和新的功能的添加。
缺点:
- 增加复杂性:桥接模式引入了抽象部分和实现部分之间的桥梁,可能会增加系统的复杂性。特别是对于简单的系统,使用桥接模式可能会显得过于复杂。
- 理解成本:由于桥接模式涉及到多个类和接口之间的关系,可能会增加新成员对系统的理解成本。需要仔细地理解抽象部分和实现部分之间的关系,以及桥接模式的设计思想。
- 过度设计:在某些情况下,使用桥接模式可能会导致过度设计的问题。如果系统的抽象部分和实现部分之间的关系比较简单,使用桥接模式可能会显得不够自然和合适。
- 设计复用性:虽然桥接模式提高了系统的灵活性和扩展性,但如果不恰当地使用,可能会导致设计复用性下降。过度使用桥接模式可能会导致代码结构的过度抽象,使得代码变得难以理解和维护。
注意事项
- 桥接模式适用于系统中多个维度的变化。
- 避免过度设计,只有当两个维度中的一个或两个具有多个实现时才考虑使用桥接模式。
适用场景
- 系统有多个维度同时变化,且不希望使用多层继承。
- 想要在抽象和实现之间建立一个稳定的联系,但又不希望二者紧密耦合。
1.案例1-发送通知
需求
假设我们正在开发一个电商平台,该平台需要发送不同类型的通知给用户,例如电子邮件通知、短信通知、App推送通知等。同时,用户可能也有不同的偏好和设备,例如有些用户更喜欢通过邮件接收通知,而另一些用户则更倾向于使用手机App接收通知。
实现思路
- 通知接口(Notification):定义了发送通知的方法。
- 具体通知类(ConcreteNotification):实现了通知接口的具体通知类型,如邮件通知、短信通知、App推送通知等。
- 用户偏好(UserPreference):定义了用户的通知偏好,包含具体通知类,例如用户更喜欢接收邮件通知还是App推送通知。
- 用户类(User):包含用户的信息和偏好设置。
- 通知服务类(NotificationService):负责根据用户的偏好选择合适的通知方式进行发送。(包含用户信息)
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 使用了以下几个关键角色:
- 抽象部分(Abstraction):
- 在
JdbcTemplate
中,抽象部分代表了对数据库操作的抽象接口,例如JdbcTemplate
类本身以及它的一些方法,如query()
、update()
等。 - 这些方法定义了客户端与数据库交互的高级操作,比如查询数据、更新数据等。
- 在
- 扩充抽象类(Refined Abstraction):
- 在 JdbcTemplate 中,扩充抽象部分是对抽象部分的扩展,可以添加更多的功能或者调整现有的功能。
- 例如,你可以创建自定义的 JdbcTemplate 子类,通过添加新的方法或者重写现有方法来实现更具体的数据库操作。
- 实现部分(Implementor):
- 在
JdbcTemplate
中,实现部分代表了对底层数据库访问的实现,例如DataSource
接口和各种数据库驱动实现。 - 这些实现提供了底层的数据库连接和操作功能,但不暴露给应用程序直接使用。
- 在
- 具体实现类(Concrete Implementor):
- 具体实现类是实现部分的具体实现,比如
DriverManagerDataSource
、C3P0DataSource
等。 - 它们提供了具体的数据库连接池实现、连接配置等功能。
- 具体实现类是实现部分的具体实现,比如
// 在创建JDBC的模板类时,需要传入数据源,这样JDBC的模板类才知道连接哪个数据库
相关文章:

解锁Spring Boot中的设计模式—04.桥接模式:探索【桥接模式】的奥秘与应用实践!
桥接模式 桥接模式也称为桥梁模式、接口模式或者柄体(Handle and Body)模式,是将抽象部分与他的具体实现部分分离,使它们都可以独立地变化,通过组合的方式建立两个类之间的联系,而不是继承。 桥接模式是一种…...
[talib][python]ta-lib所有whl文件下载地址汇总
TA-Lib-0.4.28-cp312-cp312-win-amd64.whl下载地址:https://download.csdn.net/download/FL1623863129/88589956 ta-lib-0.4.25-cp311-cp311-win-amd64.whl下载地址: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 快递信息管理:2.2.2 位置信息管理:2.2.3 配送人员分配:2.2.4 路线规划:2.2.5 个人中心:2.2.6 退换快递处理:…...
锁相放大器,数字锁相放大器.C和python版的源代码
数字锁相放大器. 锁相放大器, 它是一种可以从高噪声环境中提取出特定频率信号的放大器,工作原理主要是利用正弦函数的正交性进行信号的相位检测和幅值测量。如果你对锁相放大器感兴趣,我可以给你更详细的解释。 数字锁相放大器是利用软件算法来实现提取…...

(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题
👦个人主页:Weraphael ✍🏻作者简介:目前学习C和算法 ✈️专栏:C航路 🐋 希望大家多多支持,咱一起进步!😁 如果文章对你有帮助的话 欢迎 评论💬 点赞…...

《Go 简易速速上手小册》第10章:微服务与云原生应用(2024 最新版)
文章目录 10.1 构建微服务架构 - 探索 Go 语言的微观世界10.1.1 基础知识讲解10.1.2 重点案例:订单处理系统订单服务测试服务 10.1.3 拓展案例 1:用户认证服务安装所需的包实现用户模型和存储实现 JWT 生成和验证实现认证服务测试服务 10.1.4 拓展案例 2…...
代码随想录算法训练营第34天| Leetcode 860.柠檬水找零、406.根据身高重建队列、452. 用最少数量的箭引爆气球
文章目录 Leetcode 860.柠檬水找零Leetcode 406.根据身高重建队列Leetcode 452. 用最少数量的箭引爆气球 Leetcode 860.柠檬水找零 题目链接:Leetcode 860.柠檬水找零 题目描述: 在柠檬水摊上,每一杯柠檬水的售价为 5 美元。顾客排队购买你的…...

数据结构~二叉树(基础知识)
上一篇博客我们对树有了初步了解与学习,这篇我将初步学习二叉树!!(新年快乐!) 目录 二叉树 1、定义: 2、特点: 3、基本形态: 4、二叉树的种类: &…...

AI大模型学习笔记之四:生成式人工智能(AIGC)是如何工作的?
OpenAI 发布 ChatGPT 已经1年多了,生成式人工智能(AIGC)也已经广为人知,我们常常津津乐道于 ChatGPT 和 Claude 这样的人工智能系统能够神奇地生成文本与我们对话,并且能够记忆上下文情境。 Midjunery和DALLE 这样的AI…...
bat脚本 创建计划任务 一分钟设置ntp同步周期为60s
要在Windows中使用批处理脚本(.bat)创建一个计划任务来每分钟同步一次NTP时间,你可以使用schtasks命令来创建计划任务。下面是一个示例脚本,展示了如何创建这样一个计划任务: echo off set "taskNameSyncNTP"…...
python数据分析numpy基础之mean用法和示例
1 python数据分析numpy基础之mean用法和示例 python的numpy库的mean()函数,用于计算沿指定轴(一个轴或多个轴)的算术平均值。 用法 numpy.mean(a, axisNone, dtypeNone, outNone, keepdims<no value>, *, where<no value>)描述 返回数组元素的平均值…...

微服务学习 | Springboot整合Dubbo+Nacos实现RPC调用
🏷️个人主页:鼠鼠我捏,要死了捏的主页 🏷️系列专栏:Golang全栈-专栏 🏷️个人学习笔记,若有缺误,欢迎评论区指正 前些天发现了一个巨牛的人工智能学习网站,通俗易懂&…...

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

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

文生图提示词:天气条件
天气和气候 --天气条件 Weather Conditions 涵盖了从基本的天气类型到复杂的气象现象,为描述不同的天气和气候条件提供了丰富的词汇。 Sunny 晴朗 Cloudy 多云 Overcast 阴天 Partly Cloudy 局部多云 Clear 清晰 Foggy 雾 Misty 薄雾 Hazy 朦胧 Rainy 下雨 Showers …...
【nginx实践连载-3】发布VSTO应用
要使用 Nginx 发布 VSTO 应用程序,需要将 ClickOnce 发布文件夹部署到 Nginx 服务器上。以下是一些步骤: 将 ClickOnce 发布文件夹复制到 Nginx 服务器上。确认 Nginx 配置文件中有一个指向 ClickOnce 发布文件夹的位置块。确保Nginx 配置文件中启用了 …...
【前端工程化面试题】使用 webpack 来优化前端性能/ webpack的功能
这个题目实际上就是来回答 webpack 是干啥的,你对webpack的理解,都是一个问题。 (1)对 webpack 的理解 webpack 为啥提出 webpack 是啥 webpack 的主要功能 前端开发通常是基于模块化的,为了提高开发效率࿰…...

思迈特再获国家权威认证:代码自主率98.78%
日前,思迈特软件自主研发的商业智能与数据分析软件(Smartbi Insight)通过中国赛宝实验室(工业和信息化部电子第五研究所)代码扫描测试,Smartbi Insight V11版本扫描测得代码自主率为98.78%的好成绩…...
JavaScript排序
直接看代码 <table border"1" cellspacing"0"><thead class"tou"><tr><td>选择按钮</td><td>汽车编号</td><td>汽车图片</td><td>汽车系列名称</td><td>汽车能源</…...

19c补丁后oracle属主变化,导致不能识别磁盘组
补丁后服务器重启,数据库再次无法启动 ORA01017: invalid username/password; logon denied Oracle 19c 在打上 19.23 或以上补丁版本后,存在与用户组权限相关的问题。具体表现为,Oracle 实例的运行用户(oracle)和集…...

Python:操作 Excel 折叠
💖亲爱的技术爱好者们,热烈欢迎来到 Kant2048 的博客!我是 Thomas Kant,很开心能在CSDN上与你们相遇~💖 本博客的精华专栏: 【自动化测试】 【测试经验】 【人工智能】 【Python】 Python 操作 Excel 系列 读取单元格数据按行写入设置行高和列宽自动调整行高和列宽水平…...
【磁盘】每天掌握一个Linux命令 - iostat
目录 【磁盘】每天掌握一个Linux命令 - iostat工具概述安装方式核心功能基础用法进阶操作实战案例面试题场景生产场景 注意事项 【磁盘】每天掌握一个Linux命令 - iostat 工具概述 iostat(I/O Statistics)是Linux系统下用于监视系统输入输出设备和CPU使…...

Python实现prophet 理论及参数优化
文章目录 Prophet理论及模型参数介绍Python代码完整实现prophet 添加外部数据进行模型优化 之前初步学习prophet的时候,写过一篇简单实现,后期随着对该模型的深入研究,本次记录涉及到prophet 的公式以及参数调优,从公式可以更直观…...
【论文笔记】若干矿井粉尘检测算法概述
总的来说,传统机器学习、传统机器学习与深度学习的结合、LSTM等算法所需要的数据集来源于矿井传感器测量的粉尘浓度,通过建立回归模型来预测未来矿井的粉尘浓度。传统机器学习算法性能易受数据中极端值的影响。YOLO等计算机视觉算法所需要的数据集来源于…...

苍穹外卖--缓存菜品
1.问题说明 用户端小程序展示的菜品数据都是通过查询数据库获得,如果用户端访问量比较大,数据库访问压力随之增大 2.实现思路 通过Redis来缓存菜品数据,减少数据库查询操作。 缓存逻辑分析: ①每个分类下的菜品保持一份缓存数据…...

智能仓储的未来:自动化、AI与数据分析如何重塑物流中心
当仓库学会“思考”,物流的终极形态正在诞生 想象这样的场景: 凌晨3点,某物流中心灯火通明却空无一人。AGV机器人集群根据实时订单动态规划路径;AI视觉系统在0.1秒内扫描包裹信息;数字孪生平台正模拟次日峰值流量压力…...

分布式增量爬虫实现方案
之前我们在讨论的是分布式爬虫如何实现增量爬取。增量爬虫的目标是只爬取新产生或发生变化的页面,避免重复抓取,以节省资源和时间。 在分布式环境下,增量爬虫的实现需要考虑多个爬虫节点之间的协调和去重。 另一种思路:将增量判…...
智能AI电话机器人系统的识别能力现状与发展水平
一、引言 随着人工智能技术的飞速发展,AI电话机器人系统已经从简单的自动应答工具演变为具备复杂交互能力的智能助手。这类系统结合了语音识别、自然语言处理、情感计算和机器学习等多项前沿技术,在客户服务、营销推广、信息查询等领域发挥着越来越重要…...

Rust 开发环境搭建
环境搭建 1、开发工具RustRover 或者vs code 2、Cygwin64 安装 https://cygwin.com/install.html 在工具终端执行: rustup toolchain install stable-x86_64-pc-windows-gnu rustup default stable-x86_64-pc-windows-gnu 2、Hello World fn main() { println…...