解锁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>汽车能源</…...
第19节 Node.js Express 框架
Express 是一个为Node.js设计的web开发框架,它基于nodejs平台。 Express 简介 Express是一个简洁而灵活的node.js Web应用框架, 提供了一系列强大特性帮助你创建各种Web应用,和丰富的HTTP工具。 使用Express可以快速地搭建一个完整功能的网站。 Expre…...
【Python】 -- 趣味代码 - 小恐龙游戏
文章目录 文章目录 00 小恐龙游戏程序设计框架代码结构和功能游戏流程总结01 小恐龙游戏程序设计02 百度网盘地址00 小恐龙游戏程序设计框架 这段代码是一个基于 Pygame 的简易跑酷游戏的完整实现,玩家控制一个角色(龙)躲避障碍物(仙人掌和乌鸦)。以下是代码的详细介绍:…...
CVPR 2025 MIMO: 支持视觉指代和像素grounding 的医学视觉语言模型
CVPR 2025 | MIMO:支持视觉指代和像素对齐的医学视觉语言模型 论文信息 标题:MIMO: A medical vision language model with visual referring multimodal input and pixel grounding multimodal output作者:Yanyuan Chen, Dexuan Xu, Yu Hu…...
K8S认证|CKS题库+答案| 11. AppArmor
目录 11. AppArmor 免费获取并激活 CKA_v1.31_模拟系统 题目 开始操作: 1)、切换集群 2)、切换节点 3)、切换到 apparmor 的目录 4)、执行 apparmor 策略模块 5)、修改 pod 文件 6)、…...
盘古信息PCB行业解决方案:以全域场景重构,激活智造新未来
一、破局:PCB行业的时代之问 在数字经济蓬勃发展的浪潮中,PCB(印制电路板)作为 “电子产品之母”,其重要性愈发凸显。随着 5G、人工智能等新兴技术的加速渗透,PCB行业面临着前所未有的挑战与机遇。产品迭代…...
练习(含atoi的模拟实现,自定义类型等练习)
一、结构体大小的计算及位段 (结构体大小计算及位段 详解请看:自定义类型:结构体进阶-CSDN博客) 1.在32位系统环境,编译选项为4字节对齐,那么sizeof(A)和sizeof(B)是多少? #pragma pack(4)st…...
2025盘古石杯决赛【手机取证】
前言 第三届盘古石杯国际电子数据取证大赛决赛 最后一题没有解出来,实在找不到,希望有大佬教一下我。 还有就会议时间,我感觉不是图片时间,因为在电脑看到是其他时间用老会议系统开的会。 手机取证 1、分析鸿蒙手机检材&#x…...
网络编程(UDP编程)
思维导图 UDP基础编程(单播) 1.流程图 服务器:短信的接收方 创建套接字 (socket)-----------------------------------------》有手机指定网络信息-----------------------------------------------》有号码绑定套接字 (bind)--------------…...
中医有效性探讨
文章目录 西医是如何发展到以生物化学为药理基础的现代医学?传统医学奠基期(远古 - 17 世纪)近代医学转型期(17 世纪 - 19 世纪末)现代医学成熟期(20世纪至今) 中医的源远流长和一脉相承远古至…...
JavaScript 数据类型详解
JavaScript 数据类型详解 JavaScript 数据类型分为 原始类型(Primitive) 和 对象类型(Object) 两大类,共 8 种(ES11): 一、原始类型(7种) 1. undefined 定…...
