桥接模式-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拼接需要的参数,请求被抓取的公众号列表数据通过列表数据获取文章内容解析文章内容并通过官方接口创建草稿通过非官方接口群发创建的草稿(非认证用户,已认证用户可以通过官方接…...
django filter 统计数量 按属性去重
在Django中,如果你想要根据某个属性对查询集进行去重并统计数量,你可以使用values()方法配合annotate()方法来实现。这里有两种常见的方法来完成这个需求: 方法1:使用annotate()和Count 假设你有一个模型Item,并且你想…...
Auto-Coder使用GPT-4o完成:在用TabPFN这个模型构建一个预测未来3天涨跌的分类任务
通过akshare库,获取股票数据,并生成TabPFN这个模型 可以识别、处理的格式,写一个完整的预处理示例,并构建一个预测未来 3 天股价涨跌的分类任务 用TabPFN这个模型构建一个预测未来 3 天股价涨跌的分类任务,进行预测并输…...
屋顶变身“发电站” ,中天合创屋面分布式光伏发电项目顺利并网!
5月28日,中天合创屋面分布式光伏发电项目顺利并网发电,该项目位于内蒙古自治区鄂尔多斯市乌审旗,项目利用中天合创聚乙烯、聚丙烯仓库屋面作为场地建设光伏电站,总装机容量为9.96MWp。 项目投运后,每年可节约标煤3670…...
数据链路层的主要功能是什么
数据链路层(OSI模型第2层)的核心功能是在相邻网络节点(如交换机、主机)间提供可靠的数据帧传输服务,主要职责包括: 🔑 核心功能详解: 帧封装与解封装 封装: 将网络层下发…...
(一)单例模式
一、前言 单例模式属于六大创建型模式,即在软件设计过程中,主要关注创建对象的结果,并不关心创建对象的过程及细节。创建型设计模式将类对象的实例化过程进行抽象化接口设计,从而隐藏了类对象的实例是如何被创建的,封装了软件系统使用的具体对象类型。 六大创建型模式包括…...
Caliper 配置文件解析:fisco-bcos.json
config.yaml 文件 config.yaml 是 Caliper 的主配置文件,通常包含以下内容: test:name: fisco-bcos-test # 测试名称description: Performance test of FISCO-BCOS # 测试描述workers:type: local # 工作进程类型number: 5 # 工作进程数量monitor:type: - docker- pro…...
C#中用于控制自定义特性(Attribute)
我们来详细解释一下 [AttributeUsage(AttributeTargets.Class, AllowMultiple false, Inherited false)] 这个 C# 属性。 在 C# 中,Attribute(特性)是一种用于向程序元素(如类、方法、属性等)添加元数据的机制。Attr…...
今日行情明日机会——20250609
上证指数放量上涨,接近3400点,个股涨多跌少。 深证放量上涨,但有个小上影线,相对上证走势更弱。 2025年6月9日涨停股主要行业方向分析(基于最新图片数据) 1. 医药(11家涨停) 代表标…...
可下载旧版app屏蔽更新的app市场
软件介绍 手机用久了,app越来越臃肿,老手机卡顿成常态。这里给大家推荐个改善老手机使用体验的方法,还能帮我们卸载不需要的app。 手机现状 如今的app不断更新,看似在优化,实则内存占用越来越大,对手机性…...
LeetCode第244题_最短单词距离II
LeetCode第244题:最短单词距离II 问题描述 设计一个类,接收一个单词数组 wordsDict,并实现一个方法,该方法能够计算两个不同单词在该数组中出现位置的最短距离。 你需要实现一个 WordDistance 类: WordDistance(String[] word…...
