结构型设计模式之桥接模式

article/2025/7/12 23:25:36

文章目录

    • 1. 桥接模式概述
    • 2. 模式结构
    • 3. 桥接模式的优缺点
      • 优点
      • 缺点
    • 4. 桥接模式的应用场景
    • 5. C#代码示例
      • 5.1 简单示例 - 形状与颜色
      • 5.2 更复杂的示例 - 跨平台消息发送系统
    • 6. 桥接模式与其他模式的比较
    • 7. 真实世界中的桥接模式应用
      • 7.1 数据库驱动
      • 7.2 UI框架中的渲染机制
    • 8. 桥接模式的实现步骤
    • 9. 桥接模式在实际项目中的注意事项
    • 10. 总结
    • 学习资源

1. 桥接模式概述

桥接模式(Bridge Pattern)是一种结构型设计模式,它将抽象部分与实现部分分离,使它们可以独立变化。这种模式涉及到一个接口作为桥接,使得实体类的功能独立于接口实现类,两者可以独立地变化。

桥接模式的核心思想是:将抽象与实现解耦,使两者可以独立地变化。这种模式通过提供抽象和实现之间的桥接结构,来实现两者的解耦。

2. 模式结构

桥接模式主要包含以下核心角色:

桥接 >
Abstraction
Implementor implementor
Operation()
RefinedAbstraction
Operation()
Implementor
OperationImpl()
ConcreteImplementorA
OperationImpl()
ConcreteImplementorB
OperationImpl()
  • 抽象(Abstraction):定义抽象类的接口,它包含一个指向实现者的引用
  • 扩展抽象(RefinedAbstraction):扩展抽象类接口
  • 实现者接口(Implementor):定义实现类的接口,该接口不必与抽象类的接口完全一致
  • 具体实现者(ConcreteImplementor):实现实现者接口并定义具体实现

3. 桥接模式的优缺点

优点

  1. 分离抽象接口及其实现部分:桥接模式使用"对象间的关联关系"解耦了抽象和实现之间固有的绑定关系,使得抽象和实现可以沿着各自的维度来变化。
  2. 提高系统的可扩展性:在两个变化维度中任意扩展一个维度,都不需要修改原有系统,符合"开闭原则"。
  3. 实现细节对客户透明:客户端不用关心实现细节,可以一致性地使用接口。

缺点

  1. 增加系统的理解与设计难度:由于聚合关系建立在抽象层,要求开发者针对抽象进行设计与编程。
  2. 需要正确地识别出系统中两个独立变化的维度:如果识别不正确,可能导致系统设计的复杂性提高。

4. 桥接模式的应用场景

以下是适合使用桥接模式的典型场景:

  1. 不希望在抽象和实现之间有固定的绑定关系:例如,需要在运行时切换不同的实现。
  2. 类的抽象以及它的实现都应该可以通过生成子类的方式加以扩充:这时桥接模式使你可以对不同的维度进行组合扩充,而不是针对每种组合都独立扩展。
  3. 对一个抽象的实现部分的修改应对客户不产生影响:客户端代码不必重新编译。
  4. 有大量的类需要管理:使用桥接模式可以将多层继承结构改为多个正交类层次结构。

常见应用场景包括:

  • 跨平台应用程序(如GUI系统对不同操作系统的支持)
  • 多种数据库驱动程序
  • 不同类型的设备驱动程序
  • 多种渲染引擎的图形系统

5. C#代码示例

5.1 简单示例 - 形状与颜色

下面是一个使用桥接模式实现不同形状和不同颜色组合的示例:

using System;// 实现者接口 - 颜色
public interface IColor
{string Fill();
}// 具体实现者A - 红色
public class Red : IColor
{public string Fill(){return "红色填充";}
}// 具体实现者B - 蓝色
public class Blue : IColor
{public string Fill(){return "蓝色填充";}
}// 抽象 - 形状
public abstract class Shape
{// 桥接:引用实现者接口protected IColor color;// 构造函数注入实现者public Shape(IColor color){this.color = color;}// 抽象操作,由子类实现public abstract void Draw();
}// 扩展抽象A - 圆形
public class Circle : Shape
{private int radius;public Circle(int radius, IColor color) : base(color){this.radius = radius;}public override void Draw(){// 使用桥接的实现者Console.WriteLine($"画一个半径为{radius}的圆,使用{color.Fill()}");}
}// 扩展抽象B - 矩形
public class Rectangle : Shape
{private int width;private int height;public Rectangle(int width, int height, IColor color) : base(color){this.width = width;this.height = height;}public override void Draw(){// 使用桥接的实现者Console.WriteLine($"画一个{width}x{height}的矩形,使用{color.Fill()}");}
}// 客户端代码
public class Client
{public static void Main(string[] args){// 创建具体实现者对象IColor red = new Red();IColor blue = new Blue();// 创建扩展抽象对象并将其与具体实现者关联Shape redCircle = new Circle(10, red);Shape blueCircle = new Circle(5, blue);Shape redRectangle = new Rectangle(20, 15, red);Shape blueRectangle = new Rectangle(10, 5, blue);// 调用抽象的操作方法redCircle.Draw();     // 输出:画一个半径为10的圆,使用红色填充blueCircle.Draw();    // 输出:画一个半径为5的圆,使用蓝色填充redRectangle.Draw();  // 输出:画一个20x15的矩形,使用红色填充blueRectangle.Draw(); // 输出:画一个10x5的矩形,使用蓝色填充}
}

5.2 更复杂的示例 - 跨平台消息发送系统

下面是一个使用桥接模式设计的跨平台消息发送系统,支持不同消息类型和不同平台:

using System;// 实现者接口 - 消息发送平台
public interface IMessageSender
{void SendMessage(string message, string recipient);
}// 具体实现者A - 电子邮件发送器
public class EmailSender : IMessageSender
{public void SendMessage(string message, string recipient){// 实际应用中会调用邮件发送APIConsole.WriteLine($"通过电子邮件发送消息给{recipient}{message}");}
}// 具体实现者B - 短信发送器
public class SmsSender : IMessageSender
{public void SendMessage(string message, string recipient){// 实际应用中会调用短信服务APIConsole.WriteLine($"通过短信发送消息给{recipient}{message}");}
}// 具体实现者C - 社交媒体发送器
public class SocialMediaSender : IMessageSender
{private string platform;public SocialMediaSender(string platform){this.platform = platform;}public void SendMessage(string message, string recipient){// 实际应用中会调用特定社交媒体APIConsole.WriteLine($"通过{platform}发送消息给{recipient}{message}");}
}// 抽象 - 消息
public abstract class Message
{// 桥接:引用消息发送平台protected IMessageSender messageSender;// 构造函数注入实现者public Message(IMessageSender messageSender){this.messageSender = messageSender;}// 抽象方法,由子类实现public abstract void Send(string recipient);
}// 扩展抽象A - 文本消息
public class TextMessage : Message
{private string text;public TextMessage(string text, IMessageSender messageSender) : base(messageSender){this.text = text;}public override void Send(string recipient){messageSender.SendMessage(text, recipient);}
}// 扩展抽象B - 紧急消息
public class UrgentMessage : Message
{private string content;public UrgentMessage(string content, IMessageSender messageSender) : base(messageSender){this.content = content;}public override void Send(string recipient){// 紧急消息添加前缀string urgentMessage = "[紧急] " + content;messageSender.SendMessage(urgentMessage, recipient);// 紧急消息可能有额外的处理,如重复发送Console.WriteLine($"紧急消息已发送,系统将在5分钟后再次发送提醒。");}
}// 扩展抽象C - 加密消息
public class EncryptedMessage : Message
{private string content;public EncryptedMessage(string content, IMessageSender messageSender) : base(messageSender){this.content = content;}// 模拟加密方法private string Encrypt(string message){// 实际应用中会使用真正的加密算法return "已加密(" + message + ")";}public override void Send(string recipient){// 发送前对消息进行加密string encryptedContent = Encrypt(content);messageSender.SendMessage(encryptedContent, recipient);}
}// 客户端代码
public class Client
{public static void Main(string[] args){// 创建具体实现者对象IMessageSender emailSender = new EmailSender();IMessageSender smsSender = new SmsSender();IMessageSender wechatSender = new SocialMediaSender("微信");// 创建不同类型的消息,并关联不同的发送平台Message textEmail = new TextMessage("周会通知:明天下午2点", emailSender);Message urgentSms = new UrgentMessage("系统故障,需要立即处理", smsSender);Message encryptedWechat = new EncryptedMessage("账户密码:123456", wechatSender);// 发送消息textEmail.Send("team@company.com");       // 通过电子邮件发送普通文本消息urgentSms.Send("13800138000");            // 通过短信发送紧急消息encryptedWechat.Send("技术小组");          // 通过微信发送加密消息}
}

6. 桥接模式与其他模式的比较

设计模式主要目的与桥接模式的区别
适配器模式使不兼容的接口能够一起工作适配器模式是事后才补救的策略,而桥接模式是事前的策略
装饰器模式向对象动态添加职责装饰器保持接口不变但增强功能,桥接模式则是分离抽象与实现
组合模式将对象组合成树形结构组合模式重在整体与部分的组织,桥接模式重在抽象与实现的分离
策略模式定义一系列算法,使它们可以互换策略模式注重多种算法的切换,桥接模式注重抽象与实现的解耦

7. 真实世界中的桥接模式应用

7.1 数据库驱动

数据库操作中的JDBC API就是桥接模式的典型应用。JDBC API(抽象)与数据库驱动(实现)分离,使得应用程序可以在不同的数据库管理系统间切换。

// 抽象:数据库操作API
public abstract class DbConnection
{protected IDbDriver driver;public DbConnection(IDbDriver driver){this.driver = driver;}public abstract void Connect(string connectionString);public abstract void Execute(string query);public abstract void Close();
}// 实现者接口:数据库驱动
public interface IDbDriver
{void ConnectToDb(string connectionString);void ExecuteQuery(string query);void CloseConnection();
}// 扩展抽象:SQL数据库连接
public class SqlConnection : DbConnection
{public SqlConnection(IDbDriver driver) : base(driver) { }public override void Connect(string connectionString){Console.WriteLine("初始化SQL连接...");driver.ConnectToDb(connectionString);}public override void Execute(string query){driver.ExecuteQuery(query);}public override void Close(){driver.CloseConnection();}
}// 具体实现者A:MySQL驱动
public class MySqlDriver : IDbDriver
{public void ConnectToDb(string connectionString){Console.WriteLine($"使用MySQL驱动连接到数据库:{connectionString}");}public void ExecuteQuery(string query){Console.WriteLine($"MySQL执行查询:{query}");}public void CloseConnection(){Console.WriteLine("关闭MySQL连接");}
}// 具体实现者B:SQL Server驱动
public class SqlServerDriver : IDbDriver
{public void ConnectToDb(string connectionString){Console.WriteLine($"使用SQL Server驱动连接到数据库:{connectionString}");}public void ExecuteQuery(string query){Console.WriteLine($"SQL Server执行查询:{query}");}public void CloseConnection(){Console.WriteLine("关闭SQL Server连接");}
}

7.2 UI框架中的渲染机制

不同操作系统平台上的UI控件渲染也经常使用桥接模式:

// 实现者接口:渲染引擎
public interface IRenderEngine
{void RenderCircle(float x, float y, float radius);void RenderRectangle(float x, float y, float width, float height);void RenderText(float x, float y, string text);
}// 具体实现者A:Windows渲染引擎
public class WindowsRenderEngine : IRenderEngine
{public void RenderCircle(float x, float y, float radius){Console.WriteLine($"使用Windows GDI+渲染圆形:({x},{y}) 半径 {radius}");}public void RenderRectangle(float x, float y, float width, float height){Console.WriteLine($"使用Windows GDI+渲染矩形:({x},{y}) 大小 {width}x{height}");}public void RenderText(float x, float y, string text){Console.WriteLine($"使用Windows字体渲染文本:({x},{y}) \"{text}\"");}
}// 具体实现者B:MacOS渲染引擎
public class MacRenderEngine : IRenderEngine
{public void RenderCircle(float x, float y, float radius){Console.WriteLine($"使用Quartz 2D渲染圆形:({x},{y}) 半径 {radius}");}public void RenderRectangle(float x, float y, float width, float height){Console.WriteLine($"使用Quartz 2D渲染矩形:({x},{y}) 大小 {width}x{height}");}public void RenderText(float x, float y, string text){Console.WriteLine($"使用Core Text渲染文本:({x},{y}) \"{text}\"");}
}// 抽象:控件
public abstract class Control
{protected IRenderEngine renderEngine;protected float x, y;public Control(IRenderEngine renderEngine, float x, float y){this.renderEngine = renderEngine;this.x = x;this.y = y;}public abstract void Draw();public abstract void Resize(float scale);
}// 扩展抽象A:按钮控件
public class Button : Control
{private string text;private float width, height;public Button(IRenderEngine renderEngine, float x, float y, float width, float height, string text) : base(renderEngine, x, y){this.width = width;this.height = height;this.text = text;}public override void Draw(){renderEngine.RenderRectangle(x, y, width, height);renderEngine.RenderText(x + width/4, y + height/2, text);}public override void Resize(float scale){width *= scale;height *= scale;}
}// 扩展抽象B:圆形图标控件
public class CircleIcon : Control
{private float radius;public CircleIcon(IRenderEngine renderEngine, float x, float y, float radius) : base(renderEngine, x, y){this.radius = radius;}public override void Draw(){renderEngine.RenderCircle(x, y, radius);}public override void Resize(float scale){radius *= scale;}
}

8. 桥接模式的实现步骤

实现桥接模式通常遵循以下步骤:

  1. 确定独立变化的维度:识别系统中可以独立变化的两个维度
  2. 设计抽象层次结构:定义一个抽象类来表示第一个维度
  3. 实现抽象层次结构:通过继承抽象类来实现第一个维度的扩展
  4. 设计实现者层次结构:定义一个实现者接口来表示第二个维度
  5. 实现具体的实现者类:创建实现者接口的具体子类
  6. 在抽象类中关联实现者接口:使用组合/聚合将两个维度桥接起来
  7. 客户端使用:客户端代码将抽象部分与其具体实现部分进行组装

9. 桥接模式在实际项目中的注意事项

  1. 正确识别变化维度:桥接模式的核心在于识别出系统中独立变化的两个或多个维度,如果维度识别不准确,可能会导致设计复杂且收益有限。

  2. 抽象层设计:抽象层应该只包含高层功能,具体细节应该委托给实现层处理。避免在抽象层中包含太多实现细节。

  3. 接口一致性:确保实现者接口的设计足够稳定,如果接口需要频繁变动,会导致所有具体实现者都需要相应修改。

  4. 与继承的对比:桥接模式使用对象组合关系代替继承关系,在面对多维度变化时能够避免类爆炸问题。在考虑使用多层继承时,可以考虑是否适合改用桥接模式。

  5. 避免过度设计:如果系统中的变化维度较少或变化不频繁,使用桥接模式可能会导致不必要的复杂性,这时应该考虑更简单的设计方案。

10. 总结

桥接模式是一种强大的结构型设计模式,它通过将抽象部分和实现部分分离,使两者能够独立变化。这种模式在处理多维度变化的系统时特别有用,可以有效避免由于多层继承导致的类爆炸问题。

桥接模式的核心优势在于:

  1. 分离接口及其实现
  2. 提高系统可扩展性
  3. 实现细节对客户端透明
  4. 减少子类的数量

在实际开发中,当我们面对"多个变化维度"这样的复杂问题时,应该考虑使用桥接模式来简化系统设计,提高代码的可维护性和灵活性。特别是在需要处理跨平台应用、多种数据库支持或设备驱动等场景时,桥接模式能够发挥其优势。

学习资源

  1. Design Patterns: Elements of Reusable Object-Oriented Software - GoF经典著作
  2. Head First Design Patterns - 生动易懂的设计模式入门书籍
  3. Refactoring.Guru - Bridge Pattern
  4. C# Design Pattern Essentials
  5. Microsoft Learn - Design Patterns

在这里插入图片描述


http://www.hkcw.cn/article/RQhdkSGAdV.shtml

相关文章

RAG系统中如何检测幻觉?

虽然我们的 RAG 系统通过将答案基于真实的医学证据来减少幻觉,但我们发现了一个关键的差距:即使有引用,系统仍然可能产生不可靠的输出。 想想看:仅仅因为一个系统可以引用来源,并不意味着它正确地使用了这些来源。 模型可能会: 从检索到的文档中提取不相关的信息不适当…

world quant教程学习

Understanding Corporate Fundamental Data 🔍 了解企业基本面数据 Lets explore fundamental data😊 Fundamentals capture the underlying business, financial and operational health of a company, usually reported every quarter. This data is t…

详解鸿蒙仓颉开发语言中的计时器

今天又到了大家喜闻乐见的科普环节,也可以说是踩坑环节,哈哈哈。今天聊一聊仓颉开发语言中的计时器,这部分可老有意思了。 为什么这么说呢,因为关于仓颉的计时器你几乎搜不到任何的文档,也没有相关的代码提示&#xf…

70多套创业商业融资计划书PPT模板分享

70多套创业商业融资计划书PPT模板分享,商业计划书、融资计划书为主的欧美风格PPT模板。 70多套创业商业融资计划书PPT模板分享:创业商业融资计划书PPT模板https://pan.quark.cn/s/e09456cd487b

基于 StarRocks + Iceberg,TRM Labs 构建 PB 级数据分析平台实践

作者: Vijay Shekhawat:TRM Labs 数据平台团队核心成员,精通实时流处理、数据湖仓架构及构建安全、高吞吐的数据分析管道,在推动 PB 级数据处理能力方面发挥了关键作用。 Andrew Fisher:TRM Labs 资深软件工程师&…

Python----目标检测(使用YOLO 模型进行线程安全推理和流媒体源)

一、线程安全推理 在多线程环境中运行YOLO 模型需要仔细考虑,以确保线程安全。Pythons threading 模块允许您同时运行多个线程,但在这些线程中使用YOLO 模型时,需要注意一些重要的安全问题。本页将指导您创建线程安全的YOLO 模型推理。 1.1、…

机器学习知识图谱——朴素贝叶斯算法

目录 一、图解朴素贝叶斯算法知识图谱 二、基本概念 三、核心思想 四、为什么叫“朴素”? 五、算法流程图 六、常见模型类型 七、优点 与 缺点 八、实战代码 (以文本分类为例) 九、应用举例 机器学习知识图谱——朴素贝叶斯算法 一、图解朴素贝叶斯算法知识图谱 该…

ollama+open-webui,本地部署自己的大模型

目录 一、效果预览 二、部署ollama 1.ollama说明 2.安装流程 2.1 windows系统 2.1.1下载安装包 2.1.2验证安装结果 2.1.3设置模型文件保存地址 2.1.4拉取大模型镜像 2.2linux系统 2.2.1下载并安装ollama 2.2.2设置环境变量 2.2.3拉取模型文件 三、部署open-webui…

大模型赋能:2D 写实数字人开启实时交互新时代

在数字化浪潮席卷全球的当下,人工智能技术不断突破创新,其中大模型驱动的 2D 写实数字人正成为实时交互领域的一颗新星,引领着行业变革,为人们带来前所未有的交互体验。 一、2D 写实数字人概述 2D 写实数字人是通过计算机图形学…

效率工具- git rebase 全解

一、前言 对于git rebase 一直不太了解,这几天想着提高下git提交质量,就发现了这个好用的指令,顺便记录一下,好加深记忆 贴出官方文档以便大家进一步学习 Git 二、rebase是作用 rebase 官方解释为变基,可以理解为移动你的分支根节点,维护一个更好的提交记录。rebase把你当前…

【开源】Python打造高效剪贴板历史管理器:实现跨平台生产力工具

📋【开源】Python打造高效剪贴板历史管理器:实现跨平台生产力工具 🌈 个人主页:创客白泽 - CSDN博客 🔥 系列专栏:🐍《Python开源项目实战》 💡 热爱不止于代码,热情源自…

π0的微调——如何基于各种开源数据集、以及私有数据集微调openpi(含我司七月的微调实践及在机械臂上的部署)

前言 25年2.4日,几个月前推出π0的公司Physical Intelligence (π)宣布正式开源π0及π0-FAST,如之前所介绍的,他们对用超过 10,000 小时的机器人数据进行了预训练 该GitHub代码仓库「 π0及π0-FAST的GitHub地址:github.com/Ph…

开源模型应用落地-qwen模型小试-Qwen3-8B-融合VLLM、MCP与Agent(七)

一、前言 随着Qwen3的开源与技术升级,其在企业中的落地场景正加速拓展至多个垂直领域。依托Agent智能体能力 和MCP协议的工具调用接口 ,Qwen3可深度融入企业业务流程,为企业提供从需求解析到自动化开发的全链路支持。 本篇将介绍如何实现Qwen3-8B模型集成MCP实现智能体交互。…

【Git】GitHub 连接失败解决方案:Failed to connect to github.com port 443 after 21090 ms: Couldn’t connect to se

文章目录 一、使用 VPN 环境下的解决方案1. 检查当前代理设置2. 配置 Git 使用代理3. 验证代理设置是否生效4. 刷新 DNS 缓存5. 重新尝试 Git 操作 二、未使用 VPN 环境下的解决方案1. 取消 Git 配置的代理2. 验证代理设置已成功移除3. 重试 Git 操作 三、总结使用 VPN 的解决方…

Java 大视界 -- Java 大数据机器学习模型在元宇宙虚拟场景智能交互中的关键技术(239)

💖亲爱的朋友们,热烈欢迎来到 青云交的博客!能与诸位在此相逢,我倍感荣幸。在这飞速更迭的时代,我们都渴望一方心灵净土,而 我的博客 正是这样温暖的所在。这里为你呈上趣味与实用兼具的知识,也…

Digital Reengineering and Localized Implementation of the Five-Dimensional Management Cycle System

A Paradigm Shift in Intelligent Hospital Governance(Preliminary draft of the first-line cooperation project) Abstract This study pioneers a transformative approach to healthcare management through the “Technology-Management-Value” (TMV) triad model, r…

Qwen3:重磅开源,重夺开源第一!(包含详细使用教程)

1.简介 Qwen3,这是 Qwen 系列大型语言模型的最新成员。我们的旗舰模型 Qwen3-235B-A22B 在代码、数学、通用能力等基准测试中,与 DeepSeek-R1、o1、o3-mini、Grok-3 和 Gemini-2.5-Pro 等顶级模型相比,表现出极具竞争力的结果。此外&#xf…

基于 Alpine 定制单功能用途(kiosk)电脑

前言 故事回到 7 年前, 在网上冲浪的时候发现了一篇介绍使用 Ubuntu 打造 kiosk 单功能用途电脑的文章, 挺好玩的, 就翻译了一下并比葫芦画瓢先后用了 CentOS 7, ArchLinux 进行了实现. 历史文章: 翻译 - 使用Ubutnu14.04和Chrome打造单功能用途电脑(大屏展示电脑) 使用CentOS…

《汇编语言》第13章 int指令——实验13 编写、应用中断例程

(1)编写并安装 int 7ch 中断例程,功能为显示一个用0结束的字符串,中断例程安装在0:200处。 参数:(dh)行号,(dl)列号,(cl&a…

大模型前处理-CPU

前处理包含哪些流程 分词 tokenizationembedding CPU可以做哪些优化 分词 分词在做什么? 什么是词元化? 词元化(Tokenization)是把一段自然语言文本拆分成更小的单元(称为“词元”,即 Token&#xff0…