【设计模式】【结构型模式】桥接模式(Bridge)

👋hi,我不是一名外包公司的员工,也不会偷吃茶水间的零食,我的梦想是能写高端CRUD
🔥 2025本人正在沉淀中… 博客更新速度++
👍 欢迎点赞、收藏、关注,跟上我的更新节奏
🎵 当你的天空突然下了大雨,那是我在为你炸乌云

文章目录

  • 一、入门
    • 什么是桥接模式?
    • 为什么要用桥接模式?
    • 如何实现桥接模式?
  • 二、桥接模式在框架源码中的运用
    • JDBC(Java 数据库连接)
      • JDBC 桥接模式工作流程
      • JDBC 的源码实现
    • Spring Web MVC
  • 三、总结
    • 桥接模式的优点
    • 桥接模式的缺点
    • 桥接模式适用场景

一、入门

什么是桥接模式?

桥接模式(Bridge Pattern)是一种结构型设计模式,核心思想是将抽象与实现分离,让它们可以独立变化。简单来说,它像一座“桥”连接了两个维度的变化,避免用继承导致代码臃肿。

为什么要用桥接模式?

这次我以大家熟悉的支付系统为例,详细说明桥接模式如何解决现实中的问题。假设我们要实现一个支持不同支付方式(支付宝、微信)和不同支付渠道(国内支付、跨境支付)的系统。
传统实现:支付方式 × 渠道 = 类爆炸:以下为代码实现

// 支付宝国内支付
class AlipayDomestic {void pay() { System.out.println("支付宝国内支付:调用国内风控API");System.out.println("支付宝国内支付:人民币结算");}
}// 支付宝跨境支付
class AlipayCrossBorder {void pay() { System.out.println("支付宝跨境支付:调用国际风控API");System.out.println("支付宝跨境支付:美元结算");}
}// 微信国内支付
class WechatDomestic {void pay() { System.out.println("微信国内支付:调用国内风控API");System.out.println("微信国内支付:人民币结算");}
}// 微信跨境支付
class WechatCrossBorder {void pay() { System.out.println("微信跨境支付:调用国际风控API");System.out.println("微信跨境支付:美元结算");}
}// 如果新增一个银联支付,需要再写两个类...
// 如果新增一个支付渠道(如港澳台专线),需要为每个支付方式创建新类...

存在问题:

  1. 重复代码:国内/跨境支付的风控和结算逻辑被重复写在每个类中。
  2. 维护困难:修改国内支付的结算规则,需要改动所有相关类。
  3. 扩展性差:新增支付方式或渠道时,需要创建大量新类。

如何实现桥接模式?

桥接(Bridge)模式包含以下主要角色

  • 抽象化(Abstraction)角色 :定义抽象类,并包含一个对实现化对象的引用。
  • 扩展抽象化(Refined Abstraction)角色 :是抽象化角色的子类,实现父类中的业务方法,并通过组合关系调用实现化角色中的业务方法。
  • 实现化(Implementor)角色 :定义实现化角色的接口,供扩展抽象化角色调用。
  • 具体实现化(Concrete Implementor)角色 :给出实现化角色接口的具体实现。

【案例】桥接模式- 改
在这里插入图片描述

桥接模式解法:解耦支付方式与渠道

核心思想

  • 抽象部分:支付方式(支付宝、微信),关注用户侧操作。
  • 实现部分:支付渠道(国内、跨境),关注底层金融操作。

抽象化 (Abstraction): PaymentMethod类,定义高层抽象接口,持有实现层对象引用。

abstract class PaymentMethod {protected PaymentChannel channel; // 关键:桥接的核心public PaymentMethod(PaymentChannel channel) {this.channel = channel;}public final void pay() {channel.applyRiskControl(); // 调用实现层doPayment();                // 自身逻辑channel.settleFunds();      // 调用实现层}protected abstract void doPayment();
}

扩展抽象化 (Refined Abstraction)Alipay类、WechatPay类。实现并扩展抽象层的业务逻辑。

// 支付宝支付
class Alipay extends PaymentMethod {public Alipay(PaymentChannel channel) {super(channel);}protected void doPayment() {System.out.println("支付宝:扫码用户付款码,扣除余额");}
}// 微信支付
class WechatPay extends PaymentMethod {public WechatPay(PaymentChannel channel) {super(channel);}protected void doPayment() {System.out.println("微信:调用微信SDK,从零钱扣款");}
}

实现化 (Implementor)PaymentChannel接口。定义底层操作的接口规范(如风控和结算),独立于抽象层变化(支付方式如何变化不影响渠道实现)。

interface PaymentChannel {void applyRiskControl(); // 风控接口void settleFunds();      // 结算接口
}
具体实现化 (Concrete Implementor)DomesticChannel, CrossBorderChannel类。具体实现底层操作(如国内渠道的身份证验证),可独立扩展(新增渠道无需修改抽象层)。
// 国内支付渠道
class DomesticChannel implements PaymentChannel {public void applyRiskControl() {System.out.println("国内风控:验证身份证 + 银行卡绑定");}public void settleFunds() {System.out.println("结算:人民币入账,T+1到账");}
}// 跨境支付渠道
class CrossBorderChannel implements PaymentChannel {public void applyRiskControl() {System.out.println("跨境风控:验证护照 + 外汇管制检查");}public void settleFunds() {System.out.println("结算:美元入账,汇率转换,T+3到账");}
}

客户端

public class Client {public static void main(String[] args) {// 创建支付渠道(实现层)PaymentChannel domestic = new DomesticChannel();PaymentChannel crossBorder = new CrossBorderChannel();// 组合支付方式和渠道(抽象层)PaymentMethod alipayDomestic = new Alipay(domestic);PaymentMethod wechatCrossBorder = new WechatPay(crossBorder);// 执行支付alipayDomestic.pay();/* 输出:开始支付流程...国内风控:验证身份证 + 银行卡绑定支付宝:扫码用户付款码,扣除余额结算:人民币入账,T+1到账支付完成!*/wechatCrossBorder.pay();/* 输出:开始支付流程...跨境风控:验证护照 + 外汇管制检查微信:调用微信SDK,从零钱扣款结算:美元入账,汇率转换,T+3到账支付完成!*/}
}

这里肯定会有UU说,我好像用装饰器模式也能实现

确实,装饰器模式在某些场景下可能与桥接模式有相似之处,但它们的核心意图和适用场景有本质区别。让我通过对比来帮你理清这两种模式的区别,以及为什么在支付系统的例子中桥接模式更合适。

桥接模式装饰器模式
核心目的分离抽象与实现,让两个维度独立扩展动态地为对象添加额外功能
关系结构组合关系(横向扩展)嵌套装饰(纵向扩展)
适用场景多个正交变化的维度(如形状×渲染方式)需要动态叠加功能(如咖啡加糖、加奶)
设计重点解耦抽象层与实现层增强对象的功能

二、桥接模式在框架源码中的运用

JDBC(Java 数据库连接)

JDBC 桥接模式工作流程

加载驱动实现类(具体实现化)

Class.forName("com.mysql.cj.jdbc.Driver"); // 触发MySQL驱动的static块注册

获取抽象层接口(桥接器选择具体实现)

Connection conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/mydb", "user", "password"
);
  • DriverManager根据URL jdbc:mysql: 找到MySQL驱动
  • 调用MySQL Driver.connect()方法,返回ConnectionImpl实例(但应用程序只看到Connection接口)

操作数据库(通过抽象层接口)

Statement stmt = conn.createStatement();
ResultSet rs = stmt.executeQuery("SELECT * FROM users");
  • 无论底层是MySQL还是Oracle,代码完全一致

JDBC 的源码实现

桥接模式角色JDBC 中的对应组件具体职责
抽象化 (Abstraction)java.sql.Connection等接口定义数据库操作的高层抽象
扩展抽象化 (Refined Abstraction)无(直接使用接口)JDBC接口已足够抽象,无需扩展
实现化 (Implementor)java.sql.Driver接口 定义数据库驱动实现的规范
具体实现化 (Concrete Implementor)各数据库驱动实现类(如com.mysql.cj.jdbc.Driver)具体实现数据库连接和操作逻辑
桥接器 (Bridge)DriverManager连接抽象层和实现层的桥梁

抽象化 (Abstraction)

  • 对应组件:java.sql.ConnectionStatementPreparedStatement 等接口
  • 核心职责:
    • 定义数据库操作的抽象接口(如执行SQL、事务管理)
    • 完全独立于具体数据库(无论是MySQL还是Oracle,接口方法一致)
public interface Connection extends Wrapper, AutoCloseable {Statement createStatement() throws SQLException;PreparedStatement prepareStatement(String sql) throws SQLException;void commit() throws SQLException;// 其他数据库操作抽象方法...
}

实现化 (Implementor)

  • 对应接口:java.sql.Driver
  • 核心职责:
    • 定义数据库驱动的规范(如何连接数据库、创建连接对象)
    • 由各数据库厂商实现(如MySQL、Oracle、PostgreSQL)
public interface Driver {Connection connect(String url, Properties info) throws SQLException;boolean acceptsURL(String url) throws SQLException;// 其他驱动核心方法...
}

具体实现化 (Concrete Implementor)

  • 对应类:各数据库的驱动实现类
    • MySQL: com.mysql.cj.jdbc.Driver
    • Oracle: oracle.jdbc.OracleDriver
    • PostgreSQL: org.postgresql.Driver
  • 核心职责
    • 实现Driver接口,提供具体的数据库连接逻辑
    • 隐藏数据库底层差异(如MySQL的协议、Oracle的专有语法)
public class Driver extends NonRegisteringDriver implements java.sql.Driver {static {// 注册驱动到DriverManagerDriverManager.registerDriver(new Driver());}public Connection connect(String url, Properties info) throws SQLException {// 创建MySQL专属的ConnectionImpl对象return new ConnectionImpl(url, info);}
}

桥接器 (Bridge)

  • 对应类java.sql.DriverManager
  • 核心职责
    • 管理所有注册的数据库驱动(Driver实现类)
    • 根据URL选择合适的具体驱动,返回抽象层接口(如Connection

关键代码逻辑:

public class DriverManager {private static final List<Driver> drivers = new CopyOnWriteArrayList<>();// 注册驱动public static void registerDriver(Driver driver) {drivers.add(driver);}// 获取连接(核心桥接逻辑)public static Connection getConnection(String url, String user, String password) {for (Driver driver : drivers) {if (driver.acceptsURL(url)) {// 调用具体驱动的connect方法return driver.connect(url, properties);}}throw new SQLException("No suitable driver found for " + url);}
}

Spring Web MVC

桥接模式的应用

  • 抽象层:HandlerAdapter(处理器适配器接口)
  • 实现层:不同处理器类型的适配器(如RequestMappingHandlerAdapter
// 抽象层:HandlerAdapter接口
public interface HandlerAdapter {boolean supports(Object handler);ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception;
}// 实现层:RequestMappingHandlerAdapter
public class RequestMappingHandlerAdapter implements HandlerAdapter {public boolean supports(Object handler) {return handler instanceof HandlerMethod;}public ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {// 处理@RequestMapping注解的方法}
}

桥接模式的作用

  • 解耦:DispatcherServlet通过HandlerAdapter调用处理器,无需关心具体处理器的类型(如@ControllerHttpRequestHandler)。
  • 扩展性:新增处理器类型只需实现HandlerAdapter接口,无需修改DispatcherServlet

三、总结

桥接模式的优点

  1. 解耦抽象与实现
    • 抽象层和实现层可以独立变化,互不影响。
    • 例如,JDBC中Connection接口(抽象层)和Driver实现(实现层)可以分别扩展。
  2. 提高扩展性
    • 新增抽象类或实现类时,无需修改现有代码,符合开闭原则。
    • 例如,新增数据库驱动只需实现Driver接口,无需修改JDBC核心代码。
  3. 减少类爆炸
    • 通过组合代替继承,避免了多层继承导致的类数量暴增。
    • 例如,支付系统中支付方式和支付渠道的组合只需M+N个类,而不是M×N个类。
  4. 运行时动态绑定
    • 可以在运行时动态切换实现。
    • 例如,JDBC中DriverManager根据URL动态选择具体的数据库驱动。
  5. 隐藏实现细节
    • 客户端只依赖抽象接口,无需关心具体实现。
    • 例如,应用程序只使用Connection接口,无需关心底层是MySQL还是Oracle。

桥接模式的缺点

  1. 增加系统复杂性
    • 需要额外设计抽象层和实现层,增加了代码量和理解难度。
    • 对于简单场景,可能显得过度设计。
  2. 设计难度较高
    • 需要准确识别系统中独立变化的维度,设计不当可能导致模式滥用。
    • 例如,如果错误地将两个强耦合的维度分离,反而会增加维护成本。
  3. 性能开销
    • 由于抽象层和实现层通过组合连接,可能会引入额外的间接调用,带来轻微的性能开销。

桥接模式适用场景

  1. 多个独立变化的维度
    • 当系统中存在两个或多个正交变化的维度,且每个维度都可能独立扩展时。
    • 经典案例:
      • 支付系统:支付方式 × 支付渠道
      • 图形库:形状 × 渲染方式
      • 跨平台UI框架:UI组件 × 操作系统API
  2. 避免多层继承
    • 当使用继承会导致类数量爆炸时,桥接模式是更好的选择。
    • 经典案例:
      • JDBC:Connection接口 × 数据库驱动
      • 物流系统:运输方式 × 物流公司
  3. 运行时切换实现
    • 当需要在运行时动态切换实现时。
    • 经典案例:
      • 日志框架:日志接口 × 日志实现(Logback、Log4j)
      • 消息通知系统:通知类型 × 发送渠道(短信、邮件、App推送)
  4. 隐藏实现细节
    • 当需要对外暴露简洁的接口,同时隐藏复杂的实现细节时。
    • 经典案例:
      • 数据库连接池:连接池接口 × 具体连接池实现(HikariCP、Druid)
      • 缓存框架:缓存接口 × 缓存实现(Redis、Memcached)

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

深度学习(1)-简单神经网络示例

我们来看一个神经网络的具体实例&#xff1a;使用Python的Keras库来学习手写数字分类。在这个例子中&#xff0c;我们要解决的问题是&#xff0c;将手写数字的灰度图像&#xff08;28像素28像素&#xff09;划分到10个类别中&#xff08;从0到9&#xff09;​。我们将使用MNIST…

深入探索 C++17 中的 std::hypot:从二维到三维的欧几里得距离计算

文章目录 1. std::hypot 的起源与背景2. 三维空间中的 std::hypot3. 为什么需要 std::hypot 而不是手动计算&#xff1f;4. 使用 std::hypot 的示例4.1 二维空间中的应用4.2 三维空间中的应用4.3 处理浮点数溢出问题 5. std::hypot 的性能与精度6. 实际应用场景6.1 计算机图形学…

面基Spring Boot项目中实用注解一

在Spring Boot项目中&#xff0c;实用注解根据功能可以分为多个类别。以下是常见的注解分类、示例说明及对比分析&#xff1a; 1. 核心配置注解 SpringBootApplication 作用&#xff1a;标记主启动类&#xff0c;组合了Configuration、EnableAutoConfiguration和ComponentScan…

【每日论文】Latent Radiance Fields with 3D-aware 2D Representations

下载论文或阅读原文&#xff0c;请点击&#xff1a;每日论文 摘要 中文 潜在3D重建技术在赋予3D语义理解和3D生成能力方面展现出巨大的潜力&#xff0c;它通过将2D特征提炼到3D空间来实现。然而&#xff0c;现有的方法在2D特征空间和3D表示之间的领域差距问题上挣扎&#xff…

CPP集群聊天服务器开发实践(七):Github上传项目

github链接&#xff1a;GitHub - arduino-ctrl/ClusterServer: 基于jsonmuduomysqlnginxredis的集群服务器与客户端通信源码 步骤如下&#xff1a; 1. github新建代码仓库&#xff0c;复制url 2. git clone https://github.com/arduino-ctrl/ClusterServer.git 3. 将项目文件…

作业。。。。。

顺序表按元素删除 参数&#xff1a;删除元素&#xff0c;顺序表 1.调用元素查找的函数 4.根据下表删除 delete_sub(list,sub); //删除元素 void delete_element(int element, Sqlist *list) …

二、从0开始卷出一个新项目之瑞萨RZT2M双核架构通信和工程构建

一、概述 RZT2M双核架构是同构多核&#xff0c;但双核针对不同应用 扩展多核架构和通信知识可参见嵌入式科普(30)一文看懂嵌入式MCU/MPU多核架构与通信 二、参考资料 用户手册&#xff1a;RZ/T2M Group Users Manual: Hardware R52内核手册&#xff1a;arm_cortex_r52_proc…

【HF设计模式】07-适配器模式 外观模式

声明&#xff1a;仅为个人学习总结&#xff0c;还请批判性查看&#xff0c;如有不同观点&#xff0c;欢迎交流。 摘要 《Head First设计模式》第7章笔记&#xff1a;结合示例应用和代码&#xff0c;介绍适配器模式和外观模式&#xff0c;包括遇到的问题、采用的解决方案、遵循…

RDMA 高性能通信技术原理

目录 文章目录 目录DMA 与 RDMARDMA 特性和优势大带宽低延时 RDMA 协议栈标准RDMA 运行原理通信通路通信模型通信方式内存注册QP 建链常规流程双向控制 Send-Receive API 流程单向数据 Write API 流程单向数据 Read API 流程 RDMA Verbs API 编程基础网络连通性RDMA C/S 程序 D…

HCIA项目实践(网络)---NAT地址转化技术

十三 NAT网络地址转换技术 13.1 什么是NAT NAT&#xff08;Network Address Translation&#xff09;地址转换技术&#xff0c;是一种将内部网络的私有 IP 地址转换为外部网络的公有 IP 地址的技术。其主要作用是实现多个内部网络设备通过一个公有 IP 地址访问外部网络&#x…

【JAVA工程师从0开始学AI】,第四步:闭包与高阶函数——用Python的“魔法函数“重构Java思维

副标题&#xff1a;当严谨的Java遇上"七十二变"的Python函数式编程 历经变量战争、语法迷雾、函数对决&#xff0c;此刻我们将踏入Python最迷人的领域——函数式编程。当Java工程师还在用接口和匿名类实现回调时&#xff0c;Python的闭包已化身"智能机器人"…

el-tree选中数据重组成树

vueelement-ui 实现el-tree选择重新生成一个已选中的值组成新的数据树&#xff0c;效果如下 <template><div class"flex"><el-tree class"tree-row" :data"list" ref"tree" :props"{children: children, label: …

测试常见问题汇总-检查表(持续完善)

WEB页面常见的问题 按钮功能的实现&#xff1a;返回按钮是否可以正常返回 信息保存提交后&#xff0c;系统是否给出“成功”的提示信息&#xff0c;列表数据是否自动刷新 没有勾选任何记录直接点【删除】&#xff0c;是否给出“请先选择记录”的提示 删除是否有删除确认框 …

java后端开发day16--字符串(二)

&#xff08;以下内容全部来自上述课程&#xff09; 1.StringBuilder 因为StringBuilder是Java已经写好的类。 java在底层对他进行了一些特殊处理。 打印对象不是地址值而是属性值。 1.概述 StringBuilder可以看成是一个容器&#xff0c;创建之后里面的内容是可变的。 作用…

C++效率掌握之STL库:vector函数全解

文章目录 1.为什么要学习vector&#xff1f;什么是vector&#xff1f;2.vector类对象的常见构造3.vector类对象的容量操作4.vector类对象的迭代器5.vector类对象的元素修改6.vector类对象的元素访问7.vector迭代器失效问题希望读者们多多三连支持小编会继续更新你们的鼓励就是我…

人工智障的软件开发-容器化编码环境就绪-java-env

指令接收&#xff1a;「需要万能开发环境」 系统警报&#xff1a;检测到主人即将陷入"环境配置地狱" 启动救赎协议&#xff1a;构建量子化开发容器 终极目标&#xff1a;让"在我机器上能跑"成为历史文物 需求分析&#xff1a;碳基生物的先天缺陷 人类开发…

kkFileView二开之pdf转图片接口

kkFileView二开之Pdf转图片接口 kkFileView二开系列文章&#xff1a;1 kkFileView源码下载及编译2 Pdf转图片接口2.1 背景2.2 分析2.2 接口开发2.2.1 编写Pdf转图片方法2.2.2 编写转换接口 2.3 接口测试2.3.1 Pdf文件准备2.3.2 pdf2Image 3 部署 kkFileView二开系列文章&#x…

阅读论文笔记《Efficient Estimation of Word Representations in Vector Space》

这篇文章写于2013年&#xff0c;对理解 word2vec 的发展历程挺有帮助。 本文仅适用于 Word2Vect 的复盘 引言 这篇论文致力于探索从海量数据中学习高质量单词向量的技术。当时已发现词向量能保留语义特征&#xff0c;例如 “国王 - 男人 女人≈女王”。论文打算借助该特性&am…

SQL注入(SQL Injection)详解与实战

文章目录 一、什么是SQL注入&#xff1f;二、常见SQL注入类型三、手动注入步骤&#xff08;以CTF题目为例&#xff09;四、CTF实战技巧五、自动化工具&#xff1a;SQLMap六、防御措施七、CTF例题八、资源推荐 一、什么是SQL注入&#xff1f; SQL注入是一种通过用户输入构造恶意…

维护ceph集群

1. set: 设置标志位 # ceph osd set <flag_name> # ceph osd set noout # ceph osd set nodown # ceph osd set norecover 2. unset: 清除标志位 # ceph osd unset <flag_name> # ceph osd unset noout # ceph osd unset nodown # ceph osd unset norecover 3. 标志…