解锁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>汽车能源</…...

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

高频面试之3Zookeeper
高频面试之3Zookeeper 文章目录 高频面试之3Zookeeper3.1 常用命令3.2 选举机制3.3 Zookeeper符合法则中哪两个?3.4 Zookeeper脑裂3.5 Zookeeper用来干嘛了 3.1 常用命令 ls、get、create、delete、deleteall3.2 选举机制 半数机制(过半机制࿰…...

PL0语法,分析器实现!
简介 PL/0 是一种简单的编程语言,通常用于教学编译原理。它的语法结构清晰,功能包括常量定义、变量声明、过程(子程序)定义以及基本的控制结构(如条件语句和循环语句)。 PL/0 语法规范 PL/0 是一种教学用的小型编程语言,由 Niklaus Wirth 设计,用于展示编译原理的核…...
Python 训练营打卡 Day 47
注意力热力图可视化 在day 46代码的基础上,对比不同卷积层热力图可视化的结果 import torch import torch.nn as nn import torch.optim as optim from torchvision import datasets, transforms from torch.utils.data import DataLoader import matplotlib.pypl…...
Python学习(8) ----- Python的类与对象
Python 中的类(Class)与对象(Object)是面向对象编程(OOP)的核心。我们可以通过“类是模板,对象是实例”来理解它们的关系。 🧱 一句话理解: 类就像“图纸”,对…...

Xcode 16 集成 cocoapods 报错
基于 Xcode 16 新建工程项目,集成 cocoapods 执行 pod init 报错 ### Error RuntimeError - PBXGroup attempted to initialize an object with unknown ISA PBXFileSystemSynchronizedRootGroup from attributes: {"isa">"PBXFileSystemSynchro…...

ArcGIS Pro+ArcGIS给你的地图加上北回归线!
今天来看ArcGIS Pro和ArcGIS中如何给制作的中国地图或者其他大范围地图加上北回归线。 我们将在ArcGIS Pro和ArcGIS中一同介绍。 1 ArcGIS Pro中设置北回归线 1、在ArcGIS Pro中初步设置好经纬格网等,设置经线、纬线都以10间隔显示。 2、需要插入背会归线…...

未授权访问事件频发,我们应当如何应对?
在当下,数据已成为企业和组织的核心资产,是推动业务发展、决策制定以及创新的关键驱动力。然而,未授权访问这一隐匿的安全威胁,正如同高悬的达摩克利斯之剑,时刻威胁着数据的安全,一旦触发,便可…...
基于Java项目的Karate API测试
Karate 实现了可以只编写Feature 文件进行测试,但是对于熟悉Java语言的开发或是测试人员,可以通过编程方式集成 Karate 丰富的自动化和数据断言功能。 本篇快速介绍在Java Maven项目中编写和运行测试的示例。 创建Maven项目 最简单的创建项目的方式就是创建一个目录,里面…...

Linux实现线程同步的方式有哪些?
什么是线程同步? 想象一下超市收银台:如果所有顾客(线程)同时挤向同一个收银台(共享资源),场面会一片混乱。线程同步就是给顾客们发"排队号码牌",确保: 有序访…...