「软件设计模式」桥接模式(Bridge Pattern)
深入解析桥接模式:解耦抽象与实现的艺术
一、模式思想:正交维度的优雅解耦
桥接模式(Bridge Pattern)通过分离抽象(Abstraction)与实现(Implementation),使二者可以独立扩展变化。这种结构型设计模式完美解决了多维交叉继承导致的类爆炸问题,如同在不同维度之间架设沟通的桥梁。
核心设计原则:
- 优先组合而非继承
- 抽象层与实现层独立演化
- 运行时绑定实现细节
二、场景案例:跨平台图形界面库
假设我们需要开发一个支持Windows/Linux/MacOS的图形界面库,包含按钮、输入框等控件。传统继承方式会导致:
AbstractControl
├── WindowsButton
├── LinuxButton
├── MacButton
├── WindowsInput
├── LinuxInput
└── MacInput
当新增控件类型或操作系统支持时,类数量将呈乘积增长。这正是桥接模式的用武之地。
三、模式结构解析
关键角色:
- 抽象化角色(Abstraction):定义高层控制逻辑
- 扩展抽象化(Refined Abstraction):扩展的抽象接口
- 实现化接口(Implementor):定义底层实现接口
- 具体实现化(Concrete Implementor):具体的实现类
四、C++代码实现
#include <iostream>
#include <memory>// 实现化接口:操作系统图形API
class OSGraphicsAPI {
public:virtual ~OSGraphicsAPI() = default;virtual void drawButton(float x, float y, float w, float h) = 0;virtual void drawInputBox(float x, float y, float w, float h) = 0;
};// 具体实现化:Windows实现
class WindowsAPI : public OSGraphicsAPI {
public:void drawButton(float x, float y, float w, float h) override {std::cout << "Windows按钮绘制: (" << x << "," << y << ") " << w << "x" << h << std::endl;}void drawInputBox(float x, float y, float w, float h) override {std::cout << "Windows输入框绘制: [" << x << "," << y << "] " << w << "x" << h << std::endl;}
};// 具体实现化:Linux实现
class LinuxAPI : public OSGraphicsAPI {
public:void drawButton(float x, float y, float w, float h) override {std::cout << "Linux按钮绘制: (" << x << "," << y << ") " << w << "x" << h << std::endl;}void drawInputBox(float x, float y, float w, float h) override {std::cout << "Linux输入框绘制: [" << x << "," << y << "] " << w << "x" << h << std::endl;}
};// 抽象化接口:UI控件
class UIControl {
protected:std::unique_ptr<OSGraphicsAPI> impl_;public:explicit UIControl(std::unique_ptr<OSGraphicsAPI> api) : impl_(std::move(api)) {}virtual ~UIControl() = default;virtual void render() = 0;
};// 扩展抽象化:按钮控件
class Button : public UIControl {float x_, y_, w_, h_;public:Button(std::unique_ptr<OSGraphicsAPI> api, float x, float y, float w, float h): UIControl(std::move(api)), x_(x), y_(y), w_(w), h_(h) {}void render() override {std::cout << "渲染按钮 => ";impl_->drawButton(x_, y_, w_, h_);}
};// 扩展抽象化:输入框控件
class InputBox : public UIControl {float x_, y_, w_, h_;public:InputBox(std::unique_ptr<OSGraphicsAPI> api, float x, float y, float w, float h): UIControl(std::move(api)), x_(x), y_(y), w_(w), h_(h) {}void render() override {std::cout << "渲染输入框 => ";impl_->drawInputBox(x_, y_, w_, h_);}
};// 使用示例
int main() {// Windows平台控件auto winButton = std::make_unique<Button>(std::make_unique<WindowsAPI>(), 10, 20, 100, 30);winButton->render();// Linux平台输入框auto linuxInput = std::make_unique<InputBox>(std::make_unique<LinuxAPI>(), 50, 80, 200, 25);linuxInput->render();return 0;
}
运行模式:
五、应用场景与优势
适用场景:
- 多维度独立扩展的系统(平台x功能,设备x驱动)
- 需要运行时切换实现方案
- 避免多层继承结构
独特优势:
- 正交扩展性:新增维度只需添加对应层级的类
- 单一职责原则:抽象关注逻辑,实现专注细节
- 开闭原则:各层级独立扩展,无需修改已有代码
六、模式变体与演进
- 嵌套桥接:多层桥接处理更多维度
- 结合工厂方法:动态创建具体实现
- 策略模式融合:运行时切换不同实现策略
七、性能考量与实践建议
虽然桥接模式通过间接调用带来一定性能开销,但现代计算机的优化能力使其几乎可以忽略。建议:
- 使用智能指针管理实现对象生命周期
- 优先采用接口组合而非多层继承
- 合理控制抽象层级,避免过度设计
八、总结
桥接模式为复杂系统提供了优雅的维度解耦方案,其核心价值在于:
- 分离变与不变的部分
- 建立抽象与实现的动态绑定
- 提升系统的可维护性和扩展性
当系统出现正交维度的扩展需求时,桥接模式如同架设在抽象与实现之间的智能立交桥,让不同维度的变化能够各行其道,这正是优秀软件架构设计的精髓所在。
相关文章:

「软件设计模式」桥接模式(Bridge Pattern)
深入解析桥接模式:解耦抽象与实现的艺术 一、模式思想:正交维度的优雅解耦 桥接模式(Bridge Pattern)通过分离抽象(Abstraction)与实现(Implementation),使二者可以独立…...

【Flink快速入门-5.流处理之多流转换算子】
流处理之多流转换算子 实验介绍 前面实验中介绍的算子已经能够满足我们的大部分开发需求了,但是在实际工作中有时候还会遇到一些业务场景,例如需要摄入多个输入流并将其合并处理,或者需要将一条输入流分割为多条子流,在不同的子…...

react传递函数与回调函数原理
为什么 React 允许直接传递函数? 回调函数核心逻辑 例子:父组件控制 Modal 的显示与隐藏 // 父组件 (ParentComponent.tsx) import React, { useState } from react; import { Modal, Button } from antd; import ModalContent from ./ModalContent;co…...

华为云kubernetes基于keda自动伸缩deployment副本(监听redis队列长度)
1 概述 KEDA(Kubernetes-based Event-Driven Autoscaler,网址是https://keda.sh)是在 Kubernetes 中事件驱动的弹性伸缩器,功能非常强大。不仅支持根据基础的CPU和内存指标进行伸缩,还支持根据各种消息队列中的长度、…...

Spring源码分析のBean扫描流程
文章目录 前言一、scanCandidateComponents1.1 isCandidateComponent1.1.1、排除/包含过滤器1.1.2、条件装配1.1.3、重载一1.1.4、重载二1.1.5、补充:Lookup注解 总结 前言 原生的Spring在构造ApplicationContext时,会调用refresh方法。其中就包含了扫描…...
Ubuntu安装docker:docker-desktop : 依赖: docker-ce-cli 但无法安装它、无法定位软件包 docker-ce-cli
具体错误 sudo apt-get install ./docker-desktop-amd64.deb [sudo] password for weiyu: 正在读取软件包列表... 完成 正在分析软件包的依赖关系树... 完成 正在读取状态信息... 完成 注意,选中 docker-desktop 而非 ./docker-desktop-amd64.de…...

基于大数据的奥运会获奖数据分析系统设计与实现
【大数据】基于大数据的奥运会获奖数据分析系统设计与实现(完整系统源码开发笔记详细部署教程)✅ 目录 一、项目简介二、项目界面展示三、项目视频展示 一、项目简介 该系统通过集成先进的数据抓取、处理、存储与可视化技术,为深入理解奥运会…...

数据结构 堆和priority_queue
一、堆的定义 堆(heap),是⼀棵有着特殊性质的完全⼆叉树,可以⽤来实现优先级队列(priorityqueue)。 堆需要满⾜以下性质: 1. 是⼀棵完全⼆叉树; 2. 对于树中每个结点,如…...
Dockerfile 编写推荐
一、导读 本文主要介绍在编写 docker 镜像的时候一些需要注意的事项和推荐的做法。 虽然 Dockerfile 简化了镜像构建的过程,并且把这个过程可以进行版本控制,但是不正当的 Dockerfile 使用也会导致很多问题。 docker 镜像太大。如果你经常使用镜像或者…...
【抽象代数】1.2. 半群与群
群的定义 群非空集合二元运算性质 定义1. 设 为一个非空集合,上有二元运算,满足结合律,则称或为一个半群。 定义2. 设 为半群,若元素 满足 ,则称 为 的左幺元(右幺元:)&#…...
Django中实现简单易用的分页工具
如何在Django中实现简单易用的分页工具?📚 嗨,小伙伴们!今天我们来看看如何在 Django 中实现一个超简单的分页工具。无论你是在处理博客文章、产品列表,还是用户评论,当数据量一大时,分页显得尤…...

「软件设计模式」装饰者模式(Decorator)
深入解析装饰者模式:动态扩展功能的艺术(C实现) 一、模式思想与应用场景 1.1 模式定义 装饰者模式(Decorator Pattern)是一种结构型设计模式,它通过将对象放入包含行为的特殊封装对象中,动态地…...

CI/CD(二)docker-compose安装Jenkins
1、docker-compose.yml version: 3.8services:jenkins:image: jenkins/jenkins:lts # 使用官方的 Jenkins LTS 镜像container_name: jenkinsuser: root # 如果需要以 root 用户运行ports:- "8080:8080" # Jenkins Web 界面端口- "50000:50000" # 用于 Jen…...
OpenCV机器学习(1)人工神经网络 - 多层感知器类cv::ml::ANN_MLP
操作系统:ubuntu22.04 OpenCV版本:OpenCV4.9 IDE:Visual Studio Code 编程语言:C11 算法描述 cv::ml::ANN_MLP 是 OpenCV 库中的一部分,用于实现人工神经网络 - 多层感知器(Artificial Neural Network - Multi-Layer…...
ProxySQL构建PolarDB-X标准版高可用路由服务三节点集群
ProxySQL构建PolarDB-X标准版高可用路由服务三节点集群 一、PolarDB-X标准版主备集群搭建 三台机器上传 polardbx 包,包可以从官网https://openpolardb.com/download获取,这里提供离线rpm。 1、上传 polardbx 安装包 到 /opt目录下 rpm -ivh t-pol…...

15.1 Process(进程)类
版权声明:本文为博主原创文章,转载请在显著位置标明本文出处以及作者网名,未经作者允许不得用于商业目的。 通常开发时想要获得进程是比较困难的事,必须要调用CreateToolhelpSnapshot、ProcessFirst、ProcessNext等API或者诸如 Zw…...
elasticsearch8 linux版以服务的方式启动
1.创建系统服务文件 对于使用 systemd 作为系统初始化系统的 Linux 发行版(如 CentOS 7 及以上、Ubuntu 16.04 及以上),需要创建一个 systemd 服务文件。以 root 用户或具有 sudo 权限的用户身份执行以下操作: sudo vim /etc/sy…...

小米 R3G 路由器刷机教程(Pandavan)
小米 R3G 路由器刷机教程(Pandavan) 一、前言 小米 R3G 路由器以其高性价比和稳定的性能备受用户青睐。然而,原厂固件的功能相对有限,难以满足高级用户的个性化需求。刷机不仅可以解锁路由器的潜能,还能通过第三方固…...

某大型业务系统技术栈介绍【应对面试】
微服务架构【图】 微服务架构【概念】 微服务架构,是一种架构模式,它提倡将单一应用程序划分成一组小的服务,服务之间互相协调、互相配合,为用户提供最终价值。在微服务架构中,服务与服务之间通信时,通常是…...

【区块链】零知识证明基础概念详解
🌈个人主页: 鑫宝Code 🔥热门专栏: 闲话杂谈| 炫酷HTML | JavaScript基础 💫个人格言: "如无必要,勿增实体" 文章目录 零知识证明基础概念详解引言1. 零知识证明的定义与特性1.1 基本定义1.2 三个核心…...
conda相比python好处
Conda 作为 Python 的环境和包管理工具,相比原生 Python 生态(如 pip 虚拟环境)有许多独特优势,尤其在多项目管理、依赖处理和跨平台兼容性等方面表现更优。以下是 Conda 的核心好处: 一、一站式环境管理:…...
模型参数、模型存储精度、参数与显存
模型参数量衡量单位 M:百万(Million) B:十亿(Billion) 1 B 1000 M 1B 1000M 1B1000M 参数存储精度 模型参数是固定的,但是一个参数所表示多少字节不一定,需要看这个参数以什么…...
解锁数据库简洁之道:FastAPI与SQLModel实战指南
在构建现代Web应用程序时,与数据库的交互无疑是核心环节。虽然传统的数据库操作方式(如直接编写SQL语句与psycopg2交互)赋予了我们精细的控制权,但在面对日益复杂的业务逻辑和快速迭代的需求时,这种方式的开发效率和可…...

基于当前项目通过npm包形式暴露公共组件
1.package.sjon文件配置 其中xh-flowable就是暴露出去的npm包名 2.创建tpyes文件夹,并新增内容 3.创建package文件夹...
vue3 字体颜色设置的多种方式
在Vue 3中设置字体颜色可以通过多种方式实现,这取决于你是想在组件内部直接设置,还是在CSS/SCSS/LESS等样式文件中定义。以下是几种常见的方法: 1. 内联样式 你可以直接在模板中使用style绑定来设置字体颜色。 <template><div :s…...

2025盘古石杯决赛【手机取证】
前言 第三届盘古石杯国际电子数据取证大赛决赛 最后一题没有解出来,实在找不到,希望有大佬教一下我。 还有就会议时间,我感觉不是图片时间,因为在电脑看到是其他时间用老会议系统开的会。 手机取证 1、分析鸿蒙手机检材&#x…...

前端开发面试题总结-JavaScript篇(一)
文章目录 JavaScript高频问答一、作用域与闭包1.什么是闭包(Closure)?闭包有什么应用场景和潜在问题?2.解释 JavaScript 的作用域链(Scope Chain) 二、原型与继承3.原型链是什么?如何实现继承&a…...
【C++从零实现Json-Rpc框架】第六弹 —— 服务端模块划分
一、项目背景回顾 前五弹完成了Json-Rpc协议解析、请求处理、客户端调用等基础模块搭建。 本弹重点聚焦于服务端的模块划分与架构设计,提升代码结构的可维护性与扩展性。 二、服务端模块设计目标 高内聚低耦合:各模块职责清晰,便于独立开发…...
08. C#入门系列【类的基本概念】:开启编程世界的奇妙冒险
C#入门系列【类的基本概念】:开启编程世界的奇妙冒险 嘿,各位编程小白探险家!欢迎来到 C# 的奇幻大陆!今天咱们要深入探索这片大陆上至关重要的 “建筑”—— 类!别害怕,跟着我,保准让你轻松搞…...
深入理解Optional:处理空指针异常
1. 使用Optional处理可能为空的集合 在Java开发中,集合判空是一个常见但容易出错的场景。传统方式虽然可行,但存在一些潜在问题: // 传统判空方式 if (!CollectionUtils.isEmpty(userInfoList)) {for (UserInfo userInfo : userInfoList) {…...