当前位置: 首页 > 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; 接口测试入参这么…...

CVPR 2025 MIMO: 支持视觉指代和像素grounding 的医学视觉语言模型

CVPR 2025 | MIMO&#xff1a;支持视觉指代和像素对齐的医学视觉语言模型 论文信息 标题&#xff1a;MIMO: A medical vision language model with visual referring multimodal input and pixel grounding multimodal output作者&#xff1a;Yanyuan Chen, Dexuan Xu, Yu Hu…...

FFmpeg 低延迟同屏方案

引言 在实时互动需求激增的当下&#xff0c;无论是在线教育中的师生同屏演示、远程办公的屏幕共享协作&#xff0c;还是游戏直播的画面实时传输&#xff0c;低延迟同屏已成为保障用户体验的核心指标。FFmpeg 作为一款功能强大的多媒体框架&#xff0c;凭借其灵活的编解码、数据…...

Java多线程实现之Callable接口深度解析

Java多线程实现之Callable接口深度解析 一、Callable接口概述1.1 接口定义1.2 与Runnable接口的对比1.3 Future接口与FutureTask类 二、Callable接口的基本使用方法2.1 传统方式实现Callable接口2.2 使用Lambda表达式简化Callable实现2.3 使用FutureTask类执行Callable任务 三、…...

拉力测试cuda pytorch 把 4070显卡拉满

import torch import timedef stress_test_gpu(matrix_size16384, duration300):"""对GPU进行压力测试&#xff0c;通过持续的矩阵乘法来最大化GPU利用率参数:matrix_size: 矩阵维度大小&#xff0c;增大可提高计算复杂度duration: 测试持续时间&#xff08;秒&…...

深入解析C++中的extern关键字:跨文件共享变量与函数的终极指南

&#x1f680; C extern 关键字深度解析&#xff1a;跨文件编程的终极指南 &#x1f4c5; 更新时间&#xff1a;2025年6月5日 &#x1f3f7;️ 标签&#xff1a;C | extern关键字 | 多文件编程 | 链接与声明 | 现代C 文章目录 前言&#x1f525;一、extern 是什么&#xff1f;&…...

laravel8+vue3.0+element-plus搭建方法

创建 laravel8 项目 composer create-project --prefer-dist laravel/laravel laravel8 8.* 安装 laravel/ui composer require laravel/ui 修改 package.json 文件 "devDependencies": {"vue/compiler-sfc": "^3.0.7","axios": …...

人工智能(大型语言模型 LLMs)对不同学科的影响以及由此产生的新学习方式

今天是关于AI如何在教学中增强学生的学习体验&#xff0c;我把重要信息标红了。人文学科的价值被低估了 ⬇️ 转型与必要性 人工智能正在深刻地改变教育&#xff0c;这并非炒作&#xff0c;而是已经发生的巨大变革。教育机构和教育者不能忽视它&#xff0c;试图简单地禁止学生使…...

JavaScript基础-API 和 Web API

在学习JavaScript的过程中&#xff0c;理解API&#xff08;应用程序接口&#xff09;和Web API的概念及其应用是非常重要的。这些工具极大地扩展了JavaScript的功能&#xff0c;使得开发者能够创建出功能丰富、交互性强的Web应用程序。本文将深入探讨JavaScript中的API与Web AP…...

C/C++ 中附加包含目录、附加库目录与附加依赖项详解

在 C/C 编程的编译和链接过程中&#xff0c;附加包含目录、附加库目录和附加依赖项是三个至关重要的设置&#xff0c;它们相互配合&#xff0c;确保程序能够正确引用外部资源并顺利构建。虽然在学习过程中&#xff0c;这些概念容易让人混淆&#xff0c;但深入理解它们的作用和联…...

【Linux】Linux 系统默认的目录及作用说明

博主介绍&#xff1a;✌全网粉丝23W&#xff0c;CSDN博客专家、Java领域优质创作者&#xff0c;掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域✌ 技术范围&#xff1a;SpringBoot、SpringCloud、Vue、SSM、HTML、Nodejs、Python、MySQL、PostgreSQL、大数据、物…...