当前位置: 首页 > news >正文

C++设计模式之桥接模式

文章目录

  • 一、桥接模式
  • 二、std::error_code与设计模式(桥接模式)
  • 参考

一、桥接模式

在C++中,桥接模式通常涉及以下几个角色:

  • 抽象类接口(Abstraction):定义抽象部分的接口,并维护一个指向实现部分的指针。
  • 具体抽象类(ConcreteAbstraction):继承自抽象类,实现抽象部分的接口。
  • 实现类接口(Implementor):定义实现部分的接口。
  • 具体实现类(ConcreteImplementor):实现实现类接口,并提供具体的实现。

以下是一些可能适合使用桥接模式的具体场景:

  • 图形界面工具包中的窗口和操作系统之间的连接,使得可以在不同的操作系统上使用相同的窗口和控件。
  • 手机应用程序中的不同手机平台和不同功能的组合,例如在不同的手机上实现相同的应用,或者在同一手机上实现不同的应用。
  • 汽车制造业中,汽车品牌和引擎类型之间的组合,使得可以在不同的品牌车型上使用不同的引擎。
  • 电视机制造业中,不同的电视品牌和不同的显示技术之间的组合,使得可以在不同的品牌电视上使用不同的显示技术。

总之,桥接模式适用于需要将抽象部分和实现部分分离的场景,以实现灵活性、可扩展性和解耦的设计。它可以帮助处理多个维度上的变化,并在运行时动态地切换抽象和实现的关系。

eg:手机品牌和软件是两个概念,不同的软件可以在不同的手机上,不同的手机可以有相同的软件,两者都具有很大的变动性。

如果我们单独以手机品牌或手机软件为基类来进行继承扩展的话,无疑会使类的数目剧增并且耦合性很高,(如果更改品牌或增加软件都会增加很多的变动)两种方式的结构如下:
在这里插入图片描述
在这里插入图片描述

以将两者抽象出来两个基类分别是PhoneBrand和PhoneSoft,那么在品牌类中聚合一个软件对象的基类将解决软件和手机扩展混乱的问题,这样两者的扩展就相对灵活,剪短了两者的必要联系,结构图如下:
在这里插入图片描述

// 实现类接口
class Implementor {
public:virtual void operationImpl() = 0;
};// 具体实现类 A
class ConcreteImplementorA : public Implementor {
public:void operationImpl() override {// 具体实现 A// ...}
};// 具体实现类 B
class ConcreteImplementorB : public Implementor {
public:void operationImpl() override {// 具体实现 B// ...}
};// 抽象类
class Abstraction {
protected:Implementor* implementor;public:Abstraction(Implementor* impl) : implementor(impl) {}virtual void operation() = 0;
};// 具体类 A
class ConcreteAbstractionA : public Abstraction {
public:ConcreteAbstractionA(Implementor* impl) : Abstraction(impl) {}void operation() override {// 具体类 A 的操作// ...implementor->operationImpl();  // 调用实现类接口// ...}
};// 具体类 B
class ConcreteAbstractionB : public Abstraction {
public:ConcreteAbstractionB(Implementor* impl) : Abstraction(impl) {}void operation() override {// 具体类 B 的操作// ...implementor->operationImpl();  // 调用实现类接口// ...}
};int main() {// 创建具体实现类对象Implementor* implA = new ConcreteImplementorA();Implementor* implB = new ConcreteImplementorB();// 创建具体类对象,并传入具体实现类对象Abstraction* abstractionA = new ConcreteAbstractionA(implA);Abstraction* abstractionB = new ConcreteAbstractionB(implB);// 调用具体类的操作abstractionA->operation();abstractionB->operation();delete abstractionA;delete abstractionB;delete implA;delete implB;return 0;
}

二、std::error_code与设计模式(桥接模式)

std::error_code 类图
在这里插入图片描述

标准库提供了创建std::error_code的方法,参数传std::errc就行。

//std::error_code make_error_code( std::errc e ) noexcept;#include <system_error>
#include <iostream>int main(){std::error_code ec = std::make_error_code(std::errc::invalid_argument);std::cout<<ec.message()<<"\n";// 将输出Invalid argument
}

稍微看一下std::make_error_code的实现:

  • generic_category函数其实是一个全局函数,返回的是std::error_category的单例。
  • 源码很简单,通过构造std::error_code的函数可以看到std::error_code由两部分组成,一部分是错误码的值,一部分是std::error_category的单例。再回过头来看std::error_code类图就很清楚了。
  • 这里有个问题,std::error_code的如果仅仅是通过std::make_error_code去创建,而std::errc的错误码是有限的,如果不够用的时候,希望用一些专门领域的错误码该怎么办?
  • 这个问题就是如何写自定义的错误码,std::error_code其实已经考虑到这一点了,它是可以扩展支持自定义错误码的。
inline error_code make_error_code(errc errno) noexcept {return error_code(static_cast<int>(errno), std::generic_category());
}const std::error_category& generic_category() noexcept;

std::error_code的设计实际上是桥接模式,它把抽象和实现分离了,对于错误码来说,抽象代表的是错误码的值,实现代表的是具体的错误信息,默认情况下std::errc表示错误码的值,而std::error_category表示的是错误码对应的具体错误信息。

正是因为错误码的值会在不同的领域里含义不同,所以才需要对它做抽象,而具体的错误信息也是变化的,不同领域里错误信息也不同,所以这里非常适合用桥接模式来解耦和封装抽象和实现两部分的变化。

如果要实现自己的错误码,只需要写自定义的错误码值和派生std::error_category去重写里面的错误信息相关的虚函数就行了。

eg:雅兰亭库自定义错误码的实现

图中的单例也在这里是一个全局的函数,里面有一个static instance成员:custom category
在这里插入图片描述

雅兰亭库里面struct_pack和struct_json都实现了自己的错误码,也是根据std::error_code的桥接模式去实现的。以struct_pack的error_code为例:

#include <system_error>namespace struct_pack {
enum class errc {ok = 0,no_buffer_space,invalid_argument,hash_conflict,
};namespace detail {class struct_pack_category : public std::error_category {public:virtual const char *name() const noexcept override {return "struct_pack::category";}virtual std::string message(int err_val) const override {switch (static_cast<errc>(err_val)) {case errc::ok:return "ok";case errc::no_buffer_space:return "no buffer space";case errc::invalid_argument:return "invalid argument";case errc::hash_conflict:return "hash conflict";default:return "(unrecognized error)";}}
};inline const std::error_category &category() {static struct_pack::detail::struct_pack_category instance;return instance;
}
}  // namespace detail}  // namespace struct_packinline std::error_code make_error_code(struct_pack::errc err) {return std::error_code(static_cast<int>(err),struct_pack::detail::category());
}

注意这里的make_error_code函数其实就是在抽象和实现中间建桥,从而让std::error_code变成自定义的error_code,一个关键点是实现了struct_pack_category,而不是std::error_category,它是自定义的派生于std::error_category,所以输出的信息也是自定义的错误信息。

参考

  • C++ 桥接模式讲解和代码示例
  • c++ 设计模式之桥接模式(Bridge)
  • [Back to the basic] std::error_code与设计模式
  • [Back to the basic] std::error_code与设计模式

相关文章:

C++设计模式之桥接模式

文章目录 一、桥接模式二、std::error_code与设计模式&#xff08;桥接模式&#xff09;参考 一、桥接模式 在C中&#xff0c;桥接模式通常涉及以下几个角色&#xff1a; 抽象类接口&#xff08;Abstraction&#xff09;&#xff1a;定义抽象部分的接口&#xff0c;并维护一个…...

前端速查速记系列----评论列表

小程序评论列表 效果图 wxml代码 <view id"econtent"><block wx:for"{{commentlist}}" wx:for-item"item" wx:for-index"index" wx:key"{{item.id}}"><view class"box1"><view class"…...

hiredis的安装与使用

hiredis的介绍 Hiredis 是一个用于 C 语言的轻量级、高性能的 Redis 客户端库。它提供了一组简单易用的 API&#xff0c;用于与 Redis 数据库进行交互。Hiredis 支持 Redis 的所有主要功能&#xff0c;包括字符串、哈希、列表、集合、有序集合等数据结构的读写操作&#xff0c…...

【InsCode】InsCode打造的JavaSE与Linux命令互融的伪Linux文件系统小项目

&#x1f9d1;‍&#x1f4bb;作者名称&#xff1a;DaenCode &#x1f3a4;作者简介&#xff1a;啥技术都喜欢捣鼓捣鼓&#xff0c;喜欢分享技术、经验、生活。 &#x1f60e;人生感悟&#xff1a;尝尽人生百味&#xff0c;方知世间冷暖。 &#x1f4d6;所属专栏&#xff1a;Ja…...

“深入解析JVM:探索Java虚拟机的内部机制“

标题&#xff1a;深入解析JVM&#xff1a;探索Java虚拟机的内部机制 摘要&#xff1a;本文将深入探索Java虚拟机&#xff08;JVM&#xff09;的内部机制&#xff0c;包括JVM的基本结构、内存管理、垃圾回收机制和即时编译器等。通过对JVM内部机制的详细解析&#xff0c;我们可…...

内网远程控制总结

前言 在内网渗透过程中&#xff0c;会碰到远程控制soft或者其他&#xff0c;这里针对远程控制软件做如下总结。 远程控制软件 向日葵篇 向日葵查看版本 向日葵&#xff08;可以攻击&#xff09; 针对向日葵的话其实如果有本地安装的话&#xff0c;是有可能存在漏洞的。这…...

Excel显示此值与此单元格定义的数据验证限制不匹配怎么办?

总结&#xff1a;1、在编辑excel文档的时候&#xff0c;弹出此时预测单元格定义的数据验证&#xff0c;限制不匹配的提示。2、这是我们点击菜单来的数据菜单。3、然后点击数据工具栏的数据验证下拉按钮。4、在弹出的菜单中选择数据验证的菜单项。5、然后在打开的窗口中点击左下…...

mysql(八)事务隔离级别及加锁流程详解

目录 MySQL 锁简介什么是锁锁的作用锁的种类共享排他锁共享锁排它锁 粒度锁全局锁表级锁页级锁行级锁种类 意向锁间隙临键记录锁记录锁间隙锁 加锁的流程锁的内存结构加锁的基本流程根据主键加锁根据二级索引加锁根据非索引字段查询加锁加锁规律 锁信息查看查看锁的sql语句 数据…...

华为云Stack的学习(二)

三、华为云Stack产品组件 FunsionSphere CPS 提供云平台的基础管理和业务资源&#xff08;包括计算资源和存储资源&#xff09;。采用物理服务器方式部署在管理节点。可以做集群的配置&#xff0c;扩容和运维管理。 Service OM 提供云服务的运维能力&#xff0c;采用虚拟化方…...

好用的网页制作工具就是这6个,快点来看!

对于网页设计师来说&#xff0c;好用的网页设计工具是非常重要的&#xff0c;今天本文收集了6个好用的网页设计工具供设计师自由挑选使用。在这6个好用的网页设计工具的帮助下&#xff0c;设计师将获得更高的工作效率和更精致的网页设计效果&#xff0c;接下来&#xff0c;就一…...

一文讲通物联网嵌入式

最近有很多同学问我&#xff0c;物联网近几年一直是科技的热点&#xff0c;嵌入式和物联网有什么关系呢&#xff1f;我在这里统一给大家讲解一下。 嵌入式是应用于物联网产品方向的一种嵌入式操作系统。类似于Android系统是谷歌开发的移动操作系统&#xff0c;嵌入式实际上也是…...

Unity3D Pico VR 手势识别 二

Unity3D Pico VR 手势识别_Cool-浩的博客-CSDN博客 此篇主要讲解怎么手势追踪&#xff0c;手势姿态自定义预制识别&#xff0c;不会导入SDK和配置环境的请看上一章节 环境要求 SDK 版本&#xff1a;2.3.0 及以上PICO 设备型号&#xff1a;PICO Neo3 和 PICO 4 系列PICO 设备系…...

ubuntu中使用iptables限制端口

脚本 #!/bin/bash#关闭所有端口 echo "关闭所有入口" iptables -P INPUT DROP iptables -P FORWARD DROP#允许所有已建立的连接和相关连接的回复数据包通过 iptables -A INPUT -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT#允许ping iptables -A INPUT -p…...

Orchestrator介绍二 自身高可用性方案

目录 获得 HA 的方法 一 没有高可用性 &#xff08;No high availability&#xff09; 使用场景 架构组成 架构图 二 半高可用性&#xff08;Semi HA&#xff09; 三 基于共享数据库后端高可用&#xff08;HA via shared backend&#xff09; 四 基于Raft协议高可用 五…...

成集云 | 旺店通多包裹数据同步钉钉 | 解决方案

源系统成集云目标系统 方案介绍 随着品牌电商兴起&#xff0c;线上线下开始逐渐融为一体&#xff0c;成集云以旺店通ERP系统为例&#xff0c;通过成集云-旺店通连接器&#xff0c;将旺店通ERP系统多包裹数据同步至钉钉实现数据互通&#xff0c;帮助企业解决了电商发货存在的错…...

什么是字体图标(Icon Font)?如何在网页中使用字体图标?

聚沙成塔每天进步一点点 ⭐ 专栏简介⭐ 字体图标&#xff08;Icon Font&#xff09;⭐ 如何在网页中使用字体图标⭐ 写在最后 ⭐ 专栏简介 前端入门之旅&#xff1a;探索Web开发的奇妙世界 记得点击上方或者右侧链接订阅本专栏哦 几何带你启航前端之旅 欢迎来到前端入门之旅&a…...

Blender文件云端GPU渲染

本文介绍如何在 GPU云平台vast.ai 上渲染Blender动画的技术指南&#xff0c;假设你已使用 vast.ai 并知道如何启动实例&#xff0c;这里的重要步骤是为实例选择正确的映像。 推荐&#xff1a;用 NSDT编辑器 快速搭建可编程3D场景 使用 nvidia/cuda:11.4.1-cudnn8-devel-ubuntu2…...

C++——引用

引用的概念 引用不是新定义一个变量&#xff0c;而是给已存在的变量取一个别名&#xff0c;编译器不会因为引用变量而开辟内存空间&#xff0c;它和它引用的变量公用同一块空间。 相当于是给被引用的变量取了一个小名&#xff0c;但是相当于是同一个变量。 类型& 引用变…...

Flask入门一 ——虚拟环境及Flask安装

Flask入门一 ——虚拟环境及Flask安装 在大多数标准中&#xff0c;Flask都算是小型框架&#xff0c;小到可以称为“微框架”&#xff0c;但是并不意味着他比其他框架功能少。Flask自开发伊始就被设计为可扩展的框架。Flask具有一个包含基本服务的强健核心&#xff0c;其他功能…...

接口测试json入参,不同类型参数格式书写

接口json入参&#xff0c;不同类型参数格式 1、String 入参&#xff1a;A&#xff08;String&#xff09;&#xff0c;B&#xff08;String&#xff09; 格式&#xff1a;{"A":"值a","B":"值b"} 示例&#xff1a; 接口测试入参这么…...

LeetCode - 394. 字符串解码

题目 394. 字符串解码 - 力扣&#xff08;LeetCode&#xff09; 思路 使用两个栈&#xff1a;一个存储重复次数&#xff0c;一个存储字符串 遍历输入字符串&#xff1a; 数字处理&#xff1a;遇到数字时&#xff0c;累积计算重复次数左括号处理&#xff1a;保存当前状态&a…...

Robots.txt 文件

什么是robots.txt&#xff1f; robots.txt 是一个位于网站根目录下的文本文件&#xff08;如&#xff1a;https://example.com/robots.txt&#xff09;&#xff0c;它用于指导网络爬虫&#xff08;如搜索引擎的蜘蛛程序&#xff09;如何抓取该网站的内容。这个文件遵循 Robots…...

【OSG学习笔记】Day 16: 骨骼动画与蒙皮(osgAnimation)

骨骼动画基础 骨骼动画是 3D 计算机图形中常用的技术&#xff0c;它通过以下两个主要组件实现角色动画。 骨骼系统 (Skeleton)&#xff1a;由层级结构的骨头组成&#xff0c;类似于人体骨骼蒙皮 (Mesh Skinning)&#xff1a;将模型网格顶点绑定到骨骼上&#xff0c;使骨骼移动…...

html-<abbr> 缩写或首字母缩略词

定义与作用 <abbr> 标签用于表示缩写或首字母缩略词&#xff0c;它可以帮助用户更好地理解缩写的含义&#xff0c;尤其是对于那些不熟悉该缩写的用户。 title 属性的内容提供了缩写的详细说明。当用户将鼠标悬停在缩写上时&#xff0c;会显示一个提示框。 示例&#x…...

JS设计模式(4):观察者模式

JS设计模式(4):观察者模式 一、引入 在开发中&#xff0c;我们经常会遇到这样的场景&#xff1a;一个对象的状态变化需要自动通知其他对象&#xff0c;比如&#xff1a; 电商平台中&#xff0c;商品库存变化时需要通知所有订阅该商品的用户&#xff1b;新闻网站中&#xff0…...

A2A JS SDK 完整教程:快速入门指南

目录 什么是 A2A JS SDK?A2A JS 安装与设置A2A JS 核心概念创建你的第一个 A2A JS 代理A2A JS 服务端开发A2A JS 客户端使用A2A JS 高级特性A2A JS 最佳实践A2A JS 故障排除 什么是 A2A JS SDK? A2A JS SDK 是一个专为 JavaScript/TypeScript 开发者设计的强大库&#xff…...

现有的 Redis 分布式锁库(如 Redisson)提供了哪些便利?

现有的 Redis 分布式锁库&#xff08;如 Redisson&#xff09;相比于开发者自己基于 Redis 命令&#xff08;如 SETNX, EXPIRE, DEL&#xff09;手动实现分布式锁&#xff0c;提供了巨大的便利性和健壮性。主要体现在以下几个方面&#xff1a; 原子性保证 (Atomicity)&#xff…...

零知开源——STM32F103RBT6驱动 ICM20948 九轴传感器及 vofa + 上位机可视化教程

STM32F1 本教程使用零知标准板&#xff08;STM32F103RBT6&#xff09;通过I2C驱动ICM20948九轴传感器&#xff0c;实现姿态解算&#xff0c;并通过串口将数据实时发送至VOFA上位机进行3D可视化。代码基于开源库修改优化&#xff0c;适合嵌入式及物联网开发者。在基础驱动上新增…...

Unity VR/MR开发-VR开发与传统3D开发的差异

视频讲解链接&#xff1a;【XR马斯维】VR/MR开发与传统3D开发的差异【UnityVR/MR开发教程--入门】_哔哩哔哩_bilibili...

STM32标准库-ADC数模转换器

文章目录 一、ADC1.1简介1. 2逐次逼近型ADC1.3ADC框图1.4ADC基本结构1.4.1 信号 “上车点”&#xff1a;输入模块&#xff08;GPIO、温度、V_REFINT&#xff09;1.4.2 信号 “调度站”&#xff1a;多路开关1.4.3 信号 “加工厂”&#xff1a;ADC 转换器&#xff08;规则组 注入…...