桥接模式-C++实现
桥接模式是一种结构型设计模式,它是将抽象部分和实现部分隔离,通过组合关系将抽象部分和实现部分解耦,使它们可以独立变化。
因此,桥接模式可以很好的处理两个或两个以上维度的变化。
举一个例子说明:
假设我们现在要设计一款游戏,初步需求是有两个角色(Casa 和 Titan)和两把武器:Pistol(手枪)和 Anchor(船锚)。其中Casa是一个射手,她配备的武器是Pistol,Titan是一个战士,配备的武器是Anchor。
我们如果不用桥接模式的话,可能会这样实现:
// 卡莎角色
class CasaCharacter
{
public:CasaCharacter(){this->weapon_ = "Pistol";this->damage_ = 10;}// 攻击void Attack(){std::cout << weapon_ << "开始攻击,伤害为" << damage_ << std::endl;}private:// 武器std::string weapon_;// 伤害int damage_;
};// 泰坦角色
class TitanCharacter
{
public:TitanCharacter(){this->weapon_ = "Anchor";this->damage_ = 20;}// 攻击void Attack(){std::cout << weapon_ << "开始攻击,伤害为" << damage_ << std::endl;}private:// 武器std::string weapon_;// 伤害int damage_;
};
测试:
void TestBridge()
{std::shared_ptr<CasaCharacter> casa = std::make_shared<CasaCharacter>();casa->Attack();std::shared_ptr<TitanCharacter> titan = std::make_shared<TitanCharacter>();titan->Attack();
}int main()
{// 策略模式用法// TestStrategy();// TestObserver();// TestDecorator();TestBridge();system("pause");return 0;
}
输出:
Pistol开始攻击,伤害为10
Anchor开始攻击,伤害为20
我们实现了两个类,分别是Casa角色类和Titan角色类,在构造函数里设置角色的武器和伤害,实现了攻击方法。
假如现在我们的需求变了,Casa不仅可以配备手枪,还可以配备船锚、Titan也不仅可以配备船锚,还可以配备手枪。我们现在要实现这个需求,只能再加两个类,在构造函数里设置武器和伤害。这样的设计可能会导致类的爆炸式增长,同时也不利于扩展和维护。
并且这样的实现导致我们的测试代码是一种编译时装配,我们希望我们的程序尽可能是运行时装配,这样可以写成“活”的。
接下来使用桥接模式实现:
class IWeapon
{
protected:// 武器名字std::string weapon_name_;// 武器伤害int damage_;public:virtual ~IWeapon() {}virtual void Attack() = 0;std::string GetWeaponName(){return weapon_name_;}
};// 抽象角色类
class ICharacter
{
protected:std::shared_ptr<IWeapon> weapon_;public:virtual ~ICharacter(){}virtual void Fight() = 0;void SelectWeapon(std::shared_ptr<IWeapon> _weapon){this->weapon_ = _weapon;}
};// Casa角色
class Casa: public ICharacter
{public:virtual void Fight() override{std::cout << weapon_->GetWeaponName() << "开始攻击" << std::endl;weapon_->Attack();}
};// Titan角色
class Titan: public ICharacter
{public:virtual void Fight() override{std::cout << weapon_->GetWeaponName() << "开始攻击" << std::endl;weapon_->Attack();}
};// Pistol武器
class Pistol: public IWeapon
{
public:Pistol(){weapon_name_ = "手枪";damage_ = 10;hit_rate_ = 0.1;}virtual void Attack() override{std::cout << weapon_name_ << "造成伤害" << damage_ * (1 + hit_rate_) << std::endl;}private:// 暴击率double hit_rate_;
};// Anchor武器
class Anchor: public IWeapon
{
public:Anchor(){weapon_name_ = "船锚";damage_ = 20;}virtual void Attack() override{std::cout << weapon_name_ << "造成伤害" << damage_ << std::endl;}
};
void TestBridge()
{// Casa角色std::shared_ptr<ICharacter> casa = std::make_shared<Casa>();// Titan角色std::shared_ptr<ICharacter> titan = std::make_shared<Titan>();// Pistol武器std::shared_ptr<IWeapon> pistol = std::make_shared<Pistol>();// Anchor武器std::shared_ptr<IWeapon> anchor = std::make_shared<Anchor>();// 给角色装备武器casa->SelectWeapon(pistol);titan->SelectWeapon(anchor);// 角色开始打架casa->Fight();titan->Fight();
}int main()
{// 策略模式用法// TestStrategy();// TestObserver();// TestDecorator();TestBridge();system("pause");return 0;
}
输出:
手枪开始攻击
手枪造成伤害11
船锚开始攻击
船锚造成伤害20
使用桥接模式实现了抽象角色类和抽象武器类,具体角色Casa类、具体角色Titan类、具体武器Pistol类、具体武器Anchor类。
测试代码我们通过SelectWeapon给角色装备武器,实现了运行时装配。这样我们就可以随意的给角色装备武器。
我们可以发现通过桥接模式,实现了松耦合,并且角色和武器之间的关系是组合关系,我们可以随意的组合角色和武器,任意一方发生变化都不会对另一方造成影响,也就是两个或两个以上维度的独立变化。
桥模式的主要思想是通过将一个可变的抽象部分和一个可变的实现部分分离开来,从而使得它们可以独立地变化,相互之间不会造成影响。因此,桥模式可以很好的处理两个或两个以上变化的维度,它可以写出更好的代码,也便于代码的维护和扩展。
可以对比以上代码来理解这段话。
要点总结
- Bridge模式使用“对象间的组合关系”解耦了抽象和实现之间固有的绑定关系。使得抽象和实现可以沿着各自的维度来变化。所谓的抽象和实现可以沿着各自的维度来变化,即“子类化”它们。
- Bridge模式其实类似于多继承方案,但是多继承方案往往违背单一职责原则(即一个类只有一个变化的原因),复用性比较差。
- Bridge模式一般应用于“两个非常强的变化维度”,有时一个类也有多于两个的变化维度,这时可以使用Bridge的扩展模式。
装饰模式和桥接模式的区别:
装饰模式:动态地给一个对象增加额外的功能,让这个对象变得更加复杂。
桥接模式:将抽象部分和实现部分隔离开,使它们都可以独立地变化。
桥接模式是用合成的方式实现多个对象之间的“组合”,而装饰模式是用继承的方式实现多个对象之间的“聚合”。
桥接模式的耦合度更低,多维度的东西可以拥有自己的属性和方法,即角色和武器两个维度有自己的属性和方法。装饰模式使用继承,必然拥有相同的属性和方法。
装饰模式示例
二者对比大家就会发现:
桥接模式是为了实现多个没有关联的维度的东西自由组合,这里的没有关联是指它们拥有各自的属性和方法,没有相同点。装饰模式使用了继承必然是两个种类具有相同的属性和方法,它不是为了实现两个维度之间的自由组合,而是为了实现对对象之间的一层又一层包装,调用方法时,每一层包装递归的调用上一层的包装。
相关文章:
桥接模式-C++实现
桥接模式是一种结构型设计模式,它是将抽象部分和实现部分隔离,通过组合关系将抽象部分和实现部分解耦,使它们可以独立变化。 因此,桥接模式可以很好的处理两个或两个以上维度的变化。 举一个例子说明: 假设我们现在…...

PHP字符串函数的解析
在PHP中,字符串是一种常见的数据类型,用于存储和操作文本数据。PHP提供了丰富的字符串函数,用于执行各种字符串操作,包括截取、连接、替换、搜索等。在这篇文章中,我们将深入解析一些常用的PHP字符串函数,以…...
科研学习|研究方法——使用python强大的Statsmodel 执行假设检验和线性回归
如果你使用 Python 处理数据,你可能听说过 statsmodel 库。 Statsmodels 是一个 Python 模块,它提供各种统计模型和函数来探索、分析和可视化数据。该库广泛用于学术研究、金融和数据科学。 在本文中,我们将介绍 statsmodel 库的基础知识、如…...

设计模式——责任链模式
文章目录 责任链模式的定义场景示例责任链模式实现方案责任链模式扩展责任链模式的优缺点责任链模式在框架源码中的应用 责任链模式的定义 责任链模式又称职责链模式,是一种行为型设计模式。官方描述:使多个对象都有机会处理请求,从而避免请…...
nginx得if语句内proxy_pass不允许携带url部分,如何处理
在nginx中,proxy_pass指令不能直接携带URL部分。但是,可以使用rewrite指令结合正则表达式来处理URL部分。 下面是一个示例配置,演示如何使用rewrite指令将URL中的某个部分进行替换后传递给后端服务器: location /v100/{proxy_…...
CentOS7设置 redis 开机自启动
CentOS7设置 redis 开机自启动 步骤1.创建redis.service文件2.重新加载所有服务3.设置开机自启动4.自由地使用linux系统命令4.1.启动 Redis 服务4.2.查看 Redis 状态(-l:查看完整的信息)4.3.停止 Redis 服务4.4.重启 Redis 服务 步骤 如果你傲娇,不想拷贝࿰…...

C++虚函数(定义,作用,原理,案例)
一.定义: C的虚函数是在父类(基类)中声明的的函数,它可在子类(派生类)中重写。二.作用 虚函数的目的是实现多态性,即在程序运行时根据对象的实际类型确定调用哪个函数。三.使用方法: 在基类中声明虚函数时,需要在函…...
C#中.NET 6.0 控制台应用通过EF访问新建数据库
目录 一、 操作步骤 二、编写EF模型和数据库上下文 三、 移植(Migrations)数据库 四、编写应用程序并运行 前文已经说过.NET Framework4.8 控制台应用通过EF访问新建数据库,这里的数据据库要根据事先编写好的EF模型、经过一番操作&#x…...
conda创建pytorch环境报错
昨天训练数据的时候,发现Anaconda占用C盘达到了20G(暑假在cmd状态下安装的,默认下载到了C盘),心道再创建几个环境,C盘就要爆红了,于是重装Anaconda到了D盘,不过之后的初始化并不顺利…...
数据结构-插入排序实现
文章目录 1、描述2、代码实现3、结果4、复杂度 1、描述 待排序的数组分为已排序、未排序两部分; 初始状态时,仅有第一个元素为已排序序列,第一个以外的元素为未排序序列; 此后遍历未排序序列, 将元素逐一插入到已排序的序列中&am…...
CGlib动态代理和JDK动态代理
CGlib代理模式是一种基于字节码操作的代理模式,它通过生成被代理类的子类来实现代理功能。 CGlib通过继承被代理类,生成一个代理类的子类,并重写父类的方法,在方法的前后插入相应的代理逻辑。这种方式不需要被代理类实现接口&…...

分类预测 | Matlab实现PSO-GRU-Attention粒子群算法优化门控循环单元融合注意力机制多特征分类预测
分类预测 | Matlab实现PSO-GRU-Attention粒子群算法优化门控循环单元融合注意力机制多特征分类预测 目录 分类预测 | Matlab实现PSO-GRU-Attention粒子群算法优化门控循环单元融合注意力机制多特征分类预测分类效果基本描述程序设计参考资料 分类效果 基本描述 1.Matlab实现PSO…...
Python OpenCV 视频抽帧处理并保存
上篇文章中基于OpenCV实现图像处理后,类似的,也可以对视频进行处理。OpenCV库可以将视频的每一帧读取出来,然后对每一帧图像做相应的操作,并保存成新的视频。 1. 读取视频,获取相关参数 import cv2 import numpy as…...

英伟达AI布局的新动向:H200 GPU开启生成式AI的新纪元
英伟达Nvidia是全球领先的AI计算平台和GPU制造商,近年来一直在不断推出创新的AI产品和解决方案,为各行各业的AI应用提供强大的支持。 最近,英伟达在GTC 2023大会上发布了一款专为训练和部署生成式AI模型的图形处理单元(GPU&#…...

Windows11 python3.12 安装pyqt6 pyqt6-tools
Windows11 python3.12 安装pyqt6比较容易,但pyqt6-tools一直安装不上去。出错信息如下: (venv) PS D:\python_project\pyqt6> pip install pyqt6-tools Collecting pyqt6-toolsUsing cached pyqt6_tools-6.4.2.3.3-py3-none-any.whl (29 kB) Collec…...

反弹Shell
概述 反弹shell(reverse shell)就是控制端监听在某TCP/UDP端口,被控端发起请求到该端口,并将其命令行的输入输出转到控制端。reverse shell与telnet,ssh等标准shell对应,本质上是网络概念的客户端与服务端…...
Guava RateLimiter的限流机制详解
限流是保护高并发系统的三种有效方法之一。另外两个分别是缓存和降级。限流在很多场景中都会使用到限制并发数和请求数。例如,在限时抢购的情况下,限流可以保护您自己的系统和下游系统不被巨大的流量淹没。 限流的目的是通过限制并发访问或请求或者限制…...
详解nginx的root与alias
在Nginx中,root和alias指令都可以用来指定Web服务器中的文件根目录。不过,它们之间有一些关键的区别。 root指令指定的是服务器根目录,是用于处理HTTP请求时所使用的默认根目录。例如,若root /var/www/html;,则访问htt…...
在HBuilderX中配置Vue Router的步骤
以下是在HBuilderX中配置Vue Router的步骤: 在项目中安装Vue Router,可以使用npm或yarn命令进行安装。 在src目录下创建routers.js文件,并在该文件中编写路由相关代码,例如: import Vue from vue import Router from …...
通过接口抓取公众号信息并群发
总体步骤 通过非官方接口,登陆公众号获取cookie、token通过token拼接需要的参数,请求被抓取的公众号列表数据通过列表数据获取文章内容解析文章内容并通过官方接口创建草稿通过非官方接口群发创建的草稿(非认证用户,已认证用户可以通过官方接…...

华为云AI开发平台ModelArts
华为云ModelArts:重塑AI开发流程的“智能引擎”与“创新加速器”! 在人工智能浪潮席卷全球的2025年,企业拥抱AI的意愿空前高涨,但技术门槛高、流程复杂、资源投入巨大的现实,却让许多创新构想止步于实验室。数据科学家…...

iOS 26 携众系统重磅更新,但“苹果智能”仍与国行无缘
美国西海岸的夏天,再次被苹果点燃。一年一度的全球开发者大会 WWDC25 如期而至,这不仅是开发者的盛宴,更是全球数亿苹果用户翘首以盼的科技春晚。今年,苹果依旧为我们带来了全家桶式的系统更新,包括 iOS 26、iPadOS 26…...

循环冗余码校验CRC码 算法步骤+详细实例计算
通信过程:(白话解释) 我们将原始待发送的消息称为 M M M,依据发送接收消息双方约定的生成多项式 G ( x ) G(x) G(x)(意思就是 G ( x ) G(x) G(x) 是已知的)࿰…...

对WWDC 2025 Keynote 内容的预测
借助我们以往对苹果公司发展路径的深入研究经验,以及大语言模型的分析能力,我们系统梳理了多年来苹果 WWDC 主题演讲的规律。在 WWDC 2025 即将揭幕之际,我们让 ChatGPT 对今年的 Keynote 内容进行了一个初步预测,聊作存档。等到明…...
OpenPrompt 和直接对提示词的嵌入向量进行训练有什么区别
OpenPrompt 和直接对提示词的嵌入向量进行训练有什么区别 直接训练提示词嵌入向量的核心区别 您提到的代码: prompt_embedding = initial_embedding.clone().requires_grad_(True) optimizer = torch.optim.Adam([prompt_embedding...
大语言模型(LLM)中的KV缓存压缩与动态稀疏注意力机制设计
随着大语言模型(LLM)参数规模的增长,推理阶段的内存占用和计算复杂度成为核心挑战。传统注意力机制的计算复杂度随序列长度呈二次方增长,而KV缓存的内存消耗可能高达数十GB(例如Llama2-7B处理100K token时需50GB内存&a…...

初学 pytest 记录
安装 pip install pytest用例可以是函数也可以是类中的方法 def test_func():print()class TestAdd: # def __init__(self): 在 pytest 中不可以使用__init__方法 # self.cc 12345 pytest.mark.api def test_str(self):res add(1, 2)assert res 12def test_int(self):r…...
Java线上CPU飙高问题排查全指南
一、引言 在Java应用的线上运行环境中,CPU飙高是一个常见且棘手的性能问题。当系统出现CPU飙高时,通常会导致应用响应缓慢,甚至服务不可用,严重影响用户体验和业务运行。因此,掌握一套科学有效的CPU飙高问题排查方法&…...
Linux C语言网络编程详细入门教程:如何一步步实现TCP服务端与客户端通信
文章目录 Linux C语言网络编程详细入门教程:如何一步步实现TCP服务端与客户端通信前言一、网络通信基础概念二、服务端与客户端的完整流程图解三、每一步的详细讲解和代码示例1. 创建Socket(服务端和客户端都要)2. 绑定本地地址和端口&#x…...
#Uniapp篇:chrome调试unapp适配
chrome调试设备----使用Android模拟机开发调试移动端页面 Chrome://inspect/#devices MuMu模拟器Edge浏览器:Android原生APP嵌入的H5页面元素定位 chrome://inspect/#devices uniapp单位适配 根路径下 postcss.config.js 需要装这些插件 “postcss”: “^8.5.…...