C++设计模式:桥接模式(Bridge)
什么是桥接模式?
桥接模式(Bridge Pattern)是一个用来解耦的设计模式,它将抽象层和实现层分离开,让它们可以独立变化。用最简单的话来说,就是让你能够改变抽象的功能和具体的实现,而不需要修改对方的代码。
举个例子,想象你在做一个图形绘制的程序,你有很多图形(比如圆形、方形),而且每种图形可能有不同的绘制方式(比如屏幕绘制、打印机绘制)。如果你把所有的图形和绘制方式都写在一起,每次你增加一种新的绘制方式或新图形时,你都要修改大量的代码,这样就会让系统变得很复杂。
桥接模式的思路是:把**图形(抽象)和绘制方式(实现)**分开,每一部分都可以独立变化,互不干扰。这样一来,增加新的图形或者新的绘制方式时,就不需要修改现有的代码,只需要扩展新的类即可。
桥接模式的结构
桥接模式有两个重要部分:
- 抽象部分(比如图形的类型,如圆形、方形等)
- 实现部分(比如具体的绘制方式,如屏幕绘制、打印绘制等)
这两个部分通过“桥”连接起来,形成了一个灵活可扩展的结构。下面的代码结构就能帮助你理解这一点。
桥接模式的代码示例
假设我们要实现一个图形绘制的程序,支持不同的图形(圆形、方形)和不同的绘制方式(屏幕绘制、打印机绘制)。我们来看看怎么用桥接模式来实现。
#include <iostream>
#include <string>// 绘图接口(实现类接口)
class DrawingAPI {
public:virtual void drawCircle(double x, double y, double radius) = 0;virtual ~DrawingAPI() = default;
};// 具体实现:屏幕绘制
class ScreenDrawingAPI : public DrawingAPI {
public:void drawCircle(double x, double y, double radius) override {std::cout << "在屏幕上绘制圆形,位置: (" << x << ", " << y << "), 半径: " << radius << std::endl;}
};// 具体实现:打印机绘制
class PrinterDrawingAPI : public DrawingAPI {
public:void drawCircle(double x, double y, double radius) override {std::cout << "在打印机上绘制圆形,位置: (" << x << ", " << y << "), 半径: " << radius << std::endl;}
};// 图形类(抽象类)
class Shape {
protected:DrawingAPI* drawingAPI; // 这里持有一个指向绘图实现类的指针public:Shape(DrawingAPI* api) : drawingAPI(api) {} // 通过构造函数注入具体实现类virtual void draw() = 0; // 绘制图形的接口virtual void resize(double factor) = 0; // 调整图形大小virtual ~Shape() = default;
};// 扩展的具体图形类:圆形
class Circle : public Shape {
private:double x, y, radius; // 圆形的坐标和半径public:Circle(double x, double y, double radius, DrawingAPI* api) : Shape(api), x(x), y(y), radius(radius) {}void draw() override {drawingAPI->drawCircle(x, y, radius); // 将绘制任务委托给具体实现}void resize(double factor) override {radius *= factor; // 调整圆形的半径}
};int main() {ScreenDrawingAPI screenAPI; // 创建屏幕绘制实现PrinterDrawingAPI printerAPI; // 创建打印机绘制实现// 创建圆形对象,使用不同的绘制方式Circle circle1(1, 2, 3, &screenAPI); // 在屏幕上绘制Circle circle2(5, 6, 4, &printerAPI); // 在打印机上绘制circle1.draw(); // 屏幕绘制圆形circle2.draw(); // 打印机绘制圆形circle1.resize(2.0); // 改变圆形大小circle1.draw(); // 再次绘制,使用屏幕绘制return 0;
}
代码讲解
让我们一步步来解读这段代码,看看桥接模式是如何工作的。
1. 绘图接口(DrawingAPI
)
class DrawingAPI {
public:virtual void drawCircle(double x, double y, double radius) = 0;virtual ~DrawingAPI() = default;
};
这个类定义了一个绘制圆形的方法 drawCircle
,它只是一个接口,并不做具体的绘制工作。任何具体的绘制方式(比如屏幕绘制、打印机绘制)都需要实现这个接口。
2. 具体的绘图实现(ScreenDrawingAPI
和 PrinterDrawingAPI
)
class ScreenDrawingAPI : public DrawingAPI {
public:void drawCircle(double x, double y, double radius) override {std::cout << "在屏幕上绘制圆形,位置: (" << x << ", " << y << "), 半径: " << radius << std::endl;}
};class PrinterDrawingAPI : public DrawingAPI {
public:void drawCircle(double x, double y, double radius) override {std::cout << "在打印机上绘制圆形,位置: (" << x << ", " << y << "), 半径: " << radius << std::endl;}
};
这两个类分别实现了 DrawingAPI
接口,提供了不同的绘制方式。ScreenDrawingAPI
在屏幕上绘制圆形,PrinterDrawingAPI
在打印机上绘制圆形。
3. 抽象类(Shape
)
class Shape {
protected:DrawingAPI* drawingAPI; // 持有一个绘图实现类的指针public:Shape(DrawingAPI* api) : drawingAPI(api) {} // 通过构造函数注入具体的绘图实现virtual void draw() = 0; // 绘制图形的接口virtual void resize(double factor) = 0; // 调整图形大小
};
Shape
是一个抽象类,它定义了所有图形的共同接口:draw()
和 resize()
。关键是它持有一个 DrawingAPI
的指针,这样它可以将具体的绘制任务委托给实现类。
4. 具体图形类(Circle
)
class Circle : public Shape {
private:double x, y, radius; // 圆形的坐标和半径public:Circle(double x, double y, double radius, DrawingAPI* api) : Shape(api), x(x), y(y), radius(radius) {}void draw() override {drawingAPI->drawCircle(x, y, radius); // 调用具体绘图实现的drawCircle方法}void resize(double factor) override {radius *= factor; // 改变圆形的半径}
};
Circle
类继承自 Shape
,并实现了 draw()
和 resize()
方法。它通过 drawingAPI
指针来调用具体的绘制方法,实现了与绘制方式的解耦。
5. 客户端代码
在 main
函数中,我们创建了两个 Circle
对象,分别使用了 ScreenDrawingAPI
和 PrinterDrawingAPI
作为绘制实现。通过调用 circle1.draw()
和 circle2.draw()
,我们可以看到两个不同的绘制方式。
int main() {ScreenDrawingAPI screenAPI; // 屏幕绘制实现PrinterDrawingAPI printerAPI; // 打印机绘制实现// 创建两个圆形对象,分别使用不同的绘制方式Circle circle1(1, 2, 3, &screenAPI);Circle circle2(5, 6, 4, &printerAPI);circle1.draw(); // 屏幕绘制圆形circle2.draw(); // 打印机绘制圆形circle1.resize(2.0); // 改变圆形大小circle1.draw(); // 再次绘制,使用屏幕绘制return 0;
}
总结
桥接模式的主要优点就是解耦
。我们把抽象部分(如图形类型)和实现部分(如绘制方式)分开,避免了两者之间的紧耦合。这样我们可以很方便地扩展新的图形类型或新的绘制方式,而不需要修改现有的代码。
比如,如果你以后需要支持新的绘制方式(比如在Web上绘制),你只需要实现一个新的 DrawingAPI
类,不用改动任何图形类;同样,如果你需要增加新的图形类型(比如矩形),只需要扩展 Shape
类,不需要改动任何绘制实现。
桥接模式适用于需要将抽象和实现分离,并且它们可能会独立变化的场景。
本文由mdnice多平台发布
相关文章:
C++设计模式:桥接模式(Bridge)
什么是桥接模式? 桥接模式(Bridge Pattern)是一个用来解耦的设计模式,它将抽象层和实现层分离开,让它们可以独立变化。用最简单的话来说,就是让你能够改变抽象的功能和具体的实现,而不需要修改…...
spark3.x之后时间格式数据偶发报错org.apache.spark.SparkUpgradeException
3.x之后如果你去处理2.x生成的时间字符串数据,很容易遇到一个问题 Error operating ExecuteStatement: org.apache.spark.SparkUpgradeException: You may get a different result due to the upgrading of Spark 3.0: Fail to parse 20200725__cb90fcc3_8006_46…...
spring boot框架漏洞复现
spring - java开源框架有五种 Spring MVC、SpringBoot、SpringFramework、SpringSecurity、SpringCloud spring boot版本 版本1: 直接就在根下 / 版本2:根下的必须目录 /actuator/ 端口:9093 spring boot搭建 1:直接下载源码打包 2:运行编译好的jar包:actuator-testb…...
下载安装Android Studio
(一)Android Studio下载地址 https://developer.android.google.cn/studio 滑动到 点击下载文档 打开新网页 切换到english ![](https://i-blog.csdnimg.cn/direct/b7052b434f9d4418b9d56c66cdd59fae.png 等待一会,出现 点同意后࿰…...
三、计算机视觉_08YOLO目标检测
0、前言 YOLO作为目前CV领域的扛把子,分类、检测等任务样样精通,本文将基于两个小案例,用YOLO做检测任务,看看效果如何 1、对图片内容做检测 假设我有一张名为picture.jpeg的图片,其内容如下 我将图片和代码放到了同…...
uniapp关闭sourceMap的生成,提高编译、生产打包速度
警告信息:[警告⚠] packageF\components\mpvue-echarts\echarts.min.js 文件体积超过 500KB,已跳过压缩以及 ES6 转 ES5 的处理,手机端使用过大的js库影响性能。 遇到问题:由于微信小程序引入了mpvue-echarts\echarts.min.js&…...
uniapp首页样式,实现菜单导航结构
实现菜单导航结构 1.导入字体图标库需要的文件 2.修改引用路径iconfont.css 3.导入到App.vue中 <style>import url(./static/font/iconfont.css); </style>导航区域代码 VUE代码 <template><view class"home"><!-- 导航区域 --><…...
uniapp-vue2引用了vue-inset-loader插件编译小程序报错
报错信息 Error: Vue packages version mismatch: - vue3.2.45 (D:\qjy-myApp\admin-app\node_modules\vue\index.js) - vue-template-compiler2.7.16 (D:\qjy-myApp\admin-app\node_modules\vue-template-compiler\package.json) This may cause things to work incorrectly.…...
Git命令大全(超详细)
Git 是一个分布式版本控制系统,用于跟踪计算机文件的更改,并协调多个用户之间的工作。下面是一份较为详细的 Git 命令大全,涵盖了从初始化仓库到日常使用中常见的操作。 1. 初始化与配置 设置用户信息: git config --global user.name &quo…...
【机器学习】机器学习学习笔记 - 监督学习 - 逻辑回归分类朴素贝叶斯分类支持向量机 SVM (可分类、可回归) - 04
逻辑回归分类 import numpy as np from sklearn import linear_modelX np.array([[4, 7], [3.5, 8], [3.1, 6.2], [0.5, 1], [1, 2], [1.2, 1.9], [6, 2], [5.7, 1.5], [5.4, 2.2]]) y np.array([0, 0, 0, 1, 1, 1, 2, 2, 2])# 逻辑回归分类器 # solver:求解器&a…...
常见的数据结构---数组、链表、栈的深入剖析
目录 一、数组(Array) 二、链表(Linked List) 三、栈(Stack) 四、总结 数据结构是算法的基石,是程序设计的核心基础。不同的数据结构适用于不同的场景和需求,选择合适的数据结构能…...
前端开发:构建高质量用户体验的全方位指南(含实际案例与示例)
前端开发:构建高质量用户体验的全方位指南(含实际案例与示例) 在当今数字化时代,前端技术不仅是网页和应用的门面,更是连接用户与数字世界的桥梁。一个高质量的前端开发项目不仅能够提升用户体验(UX&#…...
Istio_05_Istio架构
Istio_05_Istio架构 ArchitectureControl PlanePilotCitadelGalley Data PlaneSidecarIstio-proxyPilot-agentMetadta Exchange Ambient Architecture 如: Istio的架构(控制面、数据面) Gateway: Istio数据面的出/入口网关 Gateway分为: Ingress-gateway、Egress-gateway外部访…...
MongoDB集群分片安装部署手册
文章目录 一、集群规划1.1 集群安装规划1.2 端口规划1.3 目录创建 二、mongodb安装(三台均需要操作)2.1 下载、解压2.2 配置环境变量 三、mongodb组件配置3.1 配置config server的副本集3.1.1 config配置文件3.1.2 config server启动3.1.3 初始化config …...
摄像头测距原理
以下是测距摄像头分类的 Markdown 格式输出,方便直接复制使用: 测距摄像头分类 1. 立体视觉(Stereo Vision)摄像头 原理:模仿人眼成像,利用两台摄像头获取不同视角的图像,通过视差计算场景深…...
基于centos7.9使用shell脚本部署k8s1.25平台
k8s 环境初始化安装Harbor安装k8s安装istio和kubevirt 使用脚本部署k8s1.25版本平台,网络插件使用flannel ,容器运行时ctr,部署包括harbor仓库,服务网格、kubevirt服务等 使用的centos7.9资源配置如下: 主机IP资源ma…...
11.29周五F34-Day10打卡
文章目录 1. 问问他能不能来。解析答案:【解析答案分析】【对比分析】【拓展内容】2. 问题是他能不能做。解析答案:【解析答案分析】3. 问题是我们能否联系得上她。(什么关系?动作 or 描述?)解析答案:【解析答案分析】【对比分析】4. 我们在讨论是否要开一个会。解析答案:…...
龙迅#LT8612UX适用于HDMI 转 HDMIVGA应用领域,分辨率高达4K60HZ,内置程序,方便调试!
1. 描述 LT8612UX 是一款 HDMI 转 HDMI&VGA 转换器,可将 HDMI2.0 数据流转换为 HDMI2.0 信号和模拟 RGB 信号。它还输出 8 通道 I2S 和 SPDIF 信号,可实现高质量的 7.1 通道音频。 LT8612UX 使用最新的 ClearEdge 技术,除了原始的 HDMI…...
C#学写了一个程序记录日志的方法(Log类)
1.错误和警告信息单独生产文本进行记录; 2.日志到一定内存阈值可以打包压缩,单独存储起来,修改字段MaxLogFileSizeForCompress的值即可; 3.Log类调用举例:Log.Txt(JB.信息,“日志记录内容”,"通道1"); usi…...
时间相关转换
Timestamp(date,type) { const zeroDate = new Date(date); if(type === startTime){ zeroDate.setHours(0, 0, 0, 0); } if(type === endTime){ zeroDate.setHours(23, 59, 59, 999); } return zeroDate.getTime(); }, //**时间戳转…...
服务器挖矿
文章目录 一、确定挖矿进程并停止二、查找并清除挖矿相关文件三、检查并修复系统漏洞四、加强安全防护 一、确定挖矿进程并停止 查找挖矿进程 在Linux系统中,可以使用命令如top或htop来查看系统资源占用情况。挖矿程序通常会占用大量的CPU或GPU资源。例如ÿ…...
mac maven编译出现问题
背景 进行maven install 命令,报错: [ERROR] COMPILATION ERROR : [INFO] ------------------------------------------------------------- [ERROR] No compiler is provided in this environment. Perhaps you are running on a JRE rather than a J…...
电磁兼容(EMC):磁性材料(永磁、软磁、功能磁)详解
目录 一、磁性材料概述 二、常用磁性材料分类 1. 永磁材料 2. 软磁材料 3. 功能性磁材 三、软磁材料特点 一、磁性材料概述 磁性材料是指由过渡元素铁(Fe)、钴(Co)、镍(Ni)及其合金等组成的能够直接…...
macOS 版本对应的 Xcode 版本,以及 Xcode 历史版本下载
注:当前页面的所有Xcode下载链接均为苹果官方下载链接 ,点击将直接转至苹果官网下载。 Xcode版本Xcode发布时间对应macOS版本macOS SDKsiOS SDKswatchOS SDKstvOS SDKs下载Xcode发布日志Xcode 15.413 May 2024macOS 14.014.5 (23F73)17.5 (21F77)10.5 (…...
从语法、功能、社区和使用场景来比较 Sass 和 LESS
一:可以从语法、功能、社区和使用场景来比较 Sass 和 LESS: 1:语法 原始的 Sass 采用的是缩进而不是大括号,后续的 Sass 版本与 LESS 一样使用与 CSS 类似的语法: address {.fa.fa-mobile-phone {margin: 0 3px 0 2…...
springboot-vue excel上传导出
数据库 device_manage表 字段,id,workshop,device_number,device_name,device_model,warn_time,expired_time device_warn表 字段,id,warn_time,expired_time 后端 实体类格式 device_manage Data TableName("device_manage"…...
CTF-PWN: ret2libc
plt表与got表是什么? PLT PLT (Procedure Linkage Table) 表在 ELF 文件中的代码段(.text)中,它看起来是这样的: .plt:0x00400530 <__libc_start_mainplt>:jmp QWORD PTR [rip 0x200602] # 0x601608 <__libc_start_maingot.plt>push 0x0jmp 0x4005100…...
SickOs: 1.1靶场学习小记
学习环境 kali攻击机:Get Kali | Kali Linux vulnhub靶场:https://download.vulnhub.com/sickos/sick0s1.1.7z 靶场描述: 这次夺旗赛清晰地模拟了在安全环境下如何对网络实施黑客策略从而入侵网络的过程。这个虚拟机与我在进攻性安全认证专…...
【ArcGIS Pro实操第10期】统计某个shp文件中不同区域内的站点数
统计某个shp文件中不同区域内的站点数 方法 1:使用“空间连接 (Spatial Join)”工具方法 2:使用“点计数 (Point Count)”工具方法 3:通过“选择 (Select by Location)”统计方法 4:通过“Python 脚本 (ArcPy)”实现参考 在 ArcGI…...
JavaScript中类数组对象及其与数组的关系
JavaScript中类数组对象及其与数组的关系 1. 什么是类数组对象? 类数组对象是指那些具有 length 属性且可以通过非负整数索引访问元素的对象。虽然这些对象看起来像数组,但它们并不具备真正数组的所有特性,例如没有继承 Array.prototype 上…...
山东网站建设都有那些/如何在各种网站投放广告
本文实例讲述了静态页面html中跳转传值的JS处理技巧。分享给大家供大家参考,具体如下:在html中通过"?"传值:静态传值在跳转到的页面index2.html中接收:var nameUrlParm.parm("name");代码如下:in…...
广州商城网站建设报价/友情链接源码
目录1.算术指令1.1 比较指令1.算术指令 作用:对两个操作数栈上的值进行某种特定运算(加减乘除等),并且把结果重新压入操作数栈。分类:大体上可以分为对整数数据进行运算的指令和对浮点数进行运算的指令。对于byte、sh…...
网站群系统建设思路/排名优化关键词公司
原子性 原子性:原子操作是不能被线程调度机制中断的操作,一旦操作开始,那么它就一定可以在可能发生的“上下文切换”之前(切换到其他线程执行)执行完毕。 依赖原子性是很棘手且很危险的,除非你是并发专家&a…...
网站后台制作步骤/东莞百度搜索网站排名
通过pb文件生成的Java接口,转成postman说需要的json格式字符串,直接上代码: /*** param path* description 具体解析path路径*/public Map<String, Object> doGeneratePostManCollections(String path) {String[] params path.split(&…...
xampp怎么做网站/免费企业网站建设
小程序日历 日历 源码见https://github.com/treadpit/wx_calendar <p class"tip">日历模板面板支持手势左右滑动</p> 提供 template 模板引入 1. 引入wxml及wxss // example.wxml <import src"../../template/calendar/index.wxml"/> …...
wordpress安装404/全网营销推广
上篇文章给大家介绍了Notion的一些基本内容,但对于小白来说,上手还是有一定难度的。首先简单回顾一下上一篇文章的内容,Notion的中文直译,是「概念」的意思,这是一款将笔记、知识库和任务管理整合在一起的协作工具。它…...