设计模式(八)结构型:桥接模式详解

桥接模式(Bridge Pattern)是 GoF 23 种设计模式中的结构型模式之一,其核心价值在于将抽象部分与实现部分分离,使它们可以独立变化。它通过“组合”而非“继承”来解耦两个或多个维度的扩展,解决了传统继承体系中类爆炸(Class Explosion)的问题。桥接模式是实现“开闭原则”的典范,广泛应用于图形渲染系统、数据库驱动、跨平台 UI 框架、消息中间件等需要多维度灵活扩展的复杂系统中。它不仅是设计模式,更是一种高层次的架构解耦思想。

一、桥接模式详细介绍

桥接模式解决的是“多维度变化导致类数量指数级增长”的问题。在传统面向对象设计中,若一个系统有两个独立变化的维度(如“形状”和“颜色”),通常会通过继承创建组合类(如 RedCircleBlueCircleRedSquareBlueSquare)。当维度增加时,子类数量呈乘积增长,导致类膨胀、维护困难、扩展性差。

桥接模式通过引入“抽象-实现”分离的双层结构,将一个类的多个变化维度拆分为独立的继承层次,并通过对象组合将它们连接起来。其核心思想是:优先使用对象组合,而不是类继承

该模式涉及以下核心角色:

  • Abstraction(抽象类):定义高层控制逻辑的接口,包含一个对 Implementor 的引用。它不直接实现功能,而是将具体操作委派给 Implementor
  • RefinedAbstraction(精化抽象类):扩展 Abstraction,提供更具体的抽象行为。可以有多个层次。
  • Implementor(实现接口):定义实现层的接口,通常与平台、设备、服务等底层细节相关。它独立于 Abstraction 层演化。
  • ConcreteImplementor(具体实现类):实现 Implementor 接口,提供具体的实现细节。可以有多个,代表不同平台或策略。

桥接模式的关键在于“桥”的建立——Abstraction 持有一个 Implementor 接口的引用,运行时可以动态绑定不同的实现。这使得抽象和实现可以独立扩展:

  • 新增一种抽象(如新图形类型)只需扩展 Abstraction 层,无需修改实现。
  • 新增一种实现(如新渲染引擎)只需扩展 Implementor 层,无需修改抽象。

与“策略模式”相比,桥接模式更强调结构分离,通常用于构建稳定的框架;策略模式更强调算法替换,用于运行时动态切换行为。桥接模式的“实现”部分往往代表系统底层或外部依赖,而“抽象”部分代表业务逻辑。

二、桥接模式的UML表示

以下是桥接模式的标准 UML 类图:

extends
extends
has a
implements
implements
Abstraction
-implementor: Implementor
+Abstraction(Implementor implementor)
+operation()
RefinedAbstractionA
+operation()
RefinedAbstractionB
+operation()
«interface»
Implementor
+implementation()
ConcreteImplementorX
+implementation()
ConcreteImplementorY
+implementation()

图解说明

  • Abstraction 是抽象层的基类,持有一个 Implementor 接口的引用。
  • RefinedAbstractionARefinedAbstractionB 是具体的抽象类,重写 operation() 方法,内部调用 implementor.implementation()
  • Implementor 是实现层接口,定义底层操作。
  • ConcreteImplementorXConcreteImplementorY 是具体实现,如不同平台的渲染引擎。
  • 客户端通过组合 RefinedAbstractionConcreteImplementor,实现任意搭配,避免了类爆炸。

三、一个简单的Java程序实例

以下是一个图形渲染系统的示例,展示如何使用桥接模式分离“图形类型”和“渲染引擎”两个维度。

// 实现接口:渲染引擎
interface Renderer {void renderCircle(double radius);void renderRectangle(double width, double height);
}// 具体实现:OpenGL 渲染引擎
class OpenGLRenderer implements Renderer {@Overridepublic void renderCircle(double radius) {System.out.println("OpenGL: Drawing circle with radius " + radius);}@Overridepublic void renderRectangle(double width, double height) {System.out.println("OpenGL: Drawing rectangle " + width + "x" + height);}
}// 具体实现:SVG 渲染引擎
class SVGRenderer implements Renderer {@Overridepublic void renderCircle(double radius) {System.out.println("SVG: Generating circle element with r=" + radius);}@Overridepublic void renderRectangle(double width, double height) {System.out.println("SVG: Generating rectangle element " + width + "x" + height);}
}// 抽象类:图形
abstract class Shape {protected Renderer renderer;public Shape(Renderer renderer) {this.renderer = renderer;}public abstract void draw();
}// 精化抽象:圆形
class Circle extends Shape {private double radius;public Circle(Renderer renderer, double radius) {super(renderer);this.radius = radius;}@Overridepublic void draw() {renderer.renderCircle(radius);}
}// 精化抽象:矩形
class Rectangle extends Shape {private double width;private double height;public Rectangle(Renderer renderer, double width, double height) {super(renderer);this.width = width;this.height = height;}@Overridepublic void draw() {renderer.renderRectangle(width, height);}
}// 客户端使用示例
public class BridgePatternDemo {public static void main(String[] args) {// 创建两种渲染引擎Renderer opengl = new OpenGLRenderer();Renderer svg = new SVGRenderer();// 创建不同图形,并绑定不同渲染引擎Shape circle1 = new Circle(opengl, 5.0);Shape circle2 = new Circle(svg, 3.0);Shape rect1 = new Rectangle(opengl, 10.0, 4.0);Shape rect2 = new Rectangle(svg, 8.0, 6.0);// 调用 draw,实际执行由具体引擎决定System.out.println("=== Rendering Shapes ===");circle1.draw(); // OpenGL 渲染圆形circle2.draw(); // SVG 渲染圆形rect1.draw();   // OpenGL 渲染矩形rect2.draw();   // SVG 渲染矩形// 动态切换渲染引擎(运行时组合)System.out.println("\n=== Dynamic Engine Switching ===");Circle dynamicCircle = new Circle(opengl, 7.0);dynamicCircle.draw();// 模拟运行时切换为 SVGdynamicCircle.renderer = svg;dynamicCircle.draw();}
}

运行说明

  • Shape 是抽象层,CircleRectangle 是具体图形。
  • Renderer 是实现层,OpenGLRendererSVGRenderer 是具体渲染引擎。
  • 通过构造函数注入 Renderer,实现“抽象”与“实现”的解耦。
  • 客户端可以自由组合任意图形与任意引擎,新增图形或引擎无需修改对方代码。

四、总结

特性说明
核心目的分离多维度变化,避免类爆炸
实现机制抽象与实现分离,通过组合连接
关键优势支持独立扩展、符合开闭原则、提高系统灵活性
主要缺点增加系统复杂性,需谨慎设计接口
适用场景多平台支持、多数据库驱动、UI 框架、跨服务适配
不适用场景变化维度少、实现稳定、性能敏感(避免间接调用)

桥接模式与其它模式对比:

  • vs 继承:继承是“紧耦合”的垂直扩展,桥接是“松耦合”的水平分离。
  • vs 适配器:适配器解决接口不兼容,桥接解决结构耦合。
  • vs 策略:策略关注算法替换,桥接关注架构分层。

架构师洞见:
桥接模式是“高内聚、低耦合”架构思想的极致体现。在现代系统中,其思想已深入到微服务分层架构插件化系统多租户平台的设计中。例如,在云原生应用中,业务逻辑(抽象)与基础设施(实现)通过桥接模式分离,使同一业务可部署在 AWS、Azure 或私有云上;在数据平台中,查询引擎(抽象)与存储系统(实现)解耦,支持对接 HDFS、S3、数据库等多种数据源。

未来趋势是:桥接模式将与领域驱动设计(DDD) 结合,在“防腐层(Anti-Corruption Layer)”中用于隔离核心域与外部系统;在Serverless 架构中,函数逻辑(抽象)与运行时环境(实现)通过桥接解耦,实现跨平台部署。

掌握桥接模式,有助于设计出可演化、可扩展、可维护的复杂系统。作为架构师,应识别系统中“正交变化维度”,在设计初期就引入桥接结构,避免后期重构成本。桥接不仅是模式,更是架构的分层智慧——它教会我们:真正的灵活性,来自于对变化的预见与分离。

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

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

相关文章

【边缘填充】——图像预处理(OpenCV)

目录 1 边界复制(BORDER_REPLICATE) 2 边界反射(BOEDER_REFLECT) 3 边界反射101(BORDER_REFLECT101) 4 边界常数(BORDER_CONSTANT) 5 边界包裹(BORDER_WRAP&#xf…

git同步到github出错-几个问题-一天晚上(2025.7.29)

访问不了github 代理和加速器都正常,但是就是访问不了这个网站尝试过几种方法都不行,后面突然可以了。 之后发现一种情况会不行:同时开启 同步不了 http连接 https://blog.csdn.net/m0_73972962/article/details/146198392 一堆问题 ssh连接才…

Redis未授权访问的利用的几种方法原理以及条件

一、redis通过定时任务反弹shell1.利用条件:需要能够登录redis数据库,并且redis以root用户运行。同时/var/spool/cron目录要具有写和执行权限。二、Redis主从getshell1.原理:在Redis 4.x之后,Redis新增了模块功能,通过…

DNF 与 YUM 的区别详解:从 CentOS 7 到 CentOS 9 的演进

🍥 DNF 与 YUM 的区别详解:从 CentOS 7 到 CentOS 9 的演进标签:CentOS、YUM、DNF、Linux 包管理、系统升级、兼容性 适用版本:CentOS 7、CentOS 8、CentOS 9🧩 一、背景介绍 CentOS 中使用的包管理工具是 RedHat 系列…

mp核心功能

条件构造器mybatisPlus支持各种复杂的where条件, 满足日常的开发wrapper类就是条件构造器提供了很多子类条件构造器的用法:QueryWrapper和LambdaQueryWrapper通常用来构建select、delete、update的where条件部分UpdateWrapper和LambdaUpdateWrapper通常只有在set语句…

pcm,msd调制解调仿真

PCM(脉冲编码调制)和MSD(多符号差分)调制解调系统的MATLAB仿真代码。 PCM (脉冲编码调制) 仿真 %% PCM调制解调仿真 clear; clc; close all;% 参数设置 Fs 8000; % 采样频率 (Hz) t_duration 0.02; % 信号持续时间 (秒…

【网络安全】信息网络安全建设方案(WORD)

1.1 安全整体架构 1.2 安全建设拓扑 1.3 安全建设内容与目标 2.1 用户侧安全建设思路 2.2 用户侧安全建设拓扑 2.3 用户侧安全建设内容 2.3.1 PKI 升级改造 2.3.2 安全防护 2.3.3 安全检测 2.3.4 安全管理 3.1 跨网安全访问与交换平台安全建设思…

微服务 01

微服务是一种软件架构风格,它是以专注于单一职责的很多小型项目为基础,组合出复杂的大型应用。 (对应的是单体架构风格) 一、认识微服务 1、单体架构 单体架构:将业务的所有功能集中在一个项目中开发,打…

20250726让荣品的PRO-RK3566开发板使用TF卡启动

20250726让荣品的PRO-RK3566开发板使用TF卡启动 2025/7/26 8:58缘起:需要升级 荣品的PRO-RK3566核心板的 底板上的FPGA程序。 由于没有使用RK809的电量计功能,板子一上电就会被关机!^_于是给生产线制作了一张TF卡/启动卡,插到底板…

Selenium使用指南

🍅 点击文末小卡片,免费获取软件测试全套资料,资料在手,涨薪更快 概述selenium是网页应用中最流行的自动化测试工具,可以用来做自动化测试或者浏览器爬虫等。官网地址为:相对于另外一款web自动化测试工具QT…

[机缘参悟-235]:通过AI人工升级网络的工作方式和特征理解人的思维方式

AI人工神经网络通过模拟生物神经元连接机制、构建层级化特征提取结构,并结合数据驱动的学习方式,为理解人类思维方式提供了技术参照框架,但其本质仍是基于统计的模式匹配,与人类意识层面的思维存在根本差异。以下从其工作方式、基…

【C#补全计划:类和对象(七)—— 重写虚方法】

一、virtual和override1. 问题引入:使用里氏替换原则时,使用父类容器装载子类对象,若不使用virtual和override而是使用new,当子类调用两个类共有的方法时,调用的是父类的方法而不是子类的方法:using System…

TCPIP之常用协议

一、TCPIP之网络支撑协议 1.ARP ARP是网络层协议,在同一广播域内,将IP地址解析成MAC地址. 1.1 无故ARP 请求型无故ARP 设备在网络中不管是自动获取ip地址还是手动配置ip地址,设备都会发送请求型无故ARP检查这个ip地址是否有重复的。 应…

网络之路24:VLAN基础实验

正文共:2345 字 18 图,预估阅读时间:3 分钟目录网络之路第一章:Windows系统中的网络0、序言1、Windows系统中的网络 1.1、桌面中的网卡 1.2、命令行中的网卡 1.3、路由表 1.4、家用路由器网络之路第二章:认识企业设备2…

基于Verilog的神经网络加速器设计

本设计实现了一个高效的神经网络加速器,专注于卷积神经网络(CNN)的核心计算功能。该设计具有以下创新点: 并行处理架构:同时处理多个卷积窗口,提高计算吞吐量 动态权重加载:支持运行时更新卷积核权重 流水线优化:卷积、激活、池化三级流水线设计 可配置参数:支持不同尺寸…

基于springboot的零食商城的设计与实现/零食销售系统的设计与实现

用户:注册,登录,商品信息,团购商品,公告资讯,后台管理,在线客服,购物车,个人中心管理员:登录,个人中心,用户管理,商品类型…

《剑指offer》-算法篇-位运算

题目二进制中“1”的个数代码实现二进制中“1”的个数题目描述:输入一个整数,输出该数二进制表示中1的个数。其中负数用补码表示。思路:求“1”的个数等价于求n-1与n进行“与”运算后不等于0所需要的运算次数。注意:这里的整数可能…

项目上线中的跨域问题

本文将深入解析跨域问题的本质,并提供实用的解决方案。引言 跨域问题可以说是前端开发者的"老朋友"了,特别是在项目从开发环境迁移到生产环境时,这个问题更是频繁出现。许多开发者对跨域的理解停留在表面,导致在项目上线…

dubbo应用之3.0新特性(响应式编程)(2)

一、介绍 Dubbo 3.0 的响应式编程基于 Triple 协议和 Reactor/RxJava 实现,支持全链路异步非阻塞通信。它通过引入 Mono、Flux 等响应式类型,打通跨进程的数据流式传输,天然支持反压、限流等控制能力。相比传统基于 CompletableFuture 的异步方式,响应式编程更适用于高并发…

力扣-22.括号生成

题目链接 22.括号生成 class Solution {List<String> res new ArrayList<>();StringBuilder path new StringBuilder();void backtracking(int n, int left, int right) {if (left right 2 * n) {res.add(path.toString());return;}if (left < n) {path.a…