【设计模式】如何用C++实现依赖倒置
【设计模式】如何用C++实现依赖倒置
一、什么是依赖倒置?
依赖倒置原则(Dependency Inversion Principle,DIP)是SOLID面向对象设计原则中的一项。它的核心思想是:
- 高层模块不应该依赖于低层模块,两者都应该依赖于抽象。
- 抽象不应该依赖于细节,细节应该依赖于抽象。
这个原则的目的在于减少代码耦合性,使代码更具灵活性和扩展性。按照依赖倒置原则,我们让上层的逻辑不直接依赖底层实现,而是通过抽象(接口或抽象类)来控制两者之间的关系。
二、为什么使用依赖倒置?
在没有依赖倒置的设计中,高层模块(如业务逻辑)往往会直接依赖于低层模块(如数据访问、服务调用)。这种依赖会使得高层模块无法独立更改,一旦低层模块发生变动,所有依赖它的高层模块都需要跟着修改,导致代码维护难度和出错率增加。
通过依赖倒置可以实现以下特性:
- 更易于扩展:可以随时替换低层模块的实现而不需要改动高层模块。
- 增强测试性:可以方便地替换低层模块,便于Mock或打桩,提升了代码的可测试性。
- 提高灵活性:可以根据需求切换不同的实现,方便扩展和维护。
三、实现步骤
-
定义抽象接口(基类):定义一个抽象类
Service.h实现了一个Test纯虚函数,此抽象类不实现任何具体逻辑,仅对外提供接口Service.h
#ifndef DIP_SERVICE #define DIP_SERVICEnamespace DIP {class Service{public:virtual ~Service() = default;virtual void Test() = 0;}; }#endif -
实现接口的具体类:定义一个实现类
ServiceImpl实现构造、析构、Test等函数逻辑。ServiceImpl.h
#ifndef DIP_SERVICEIMPL #define DIP_SERVICEIMPL #include "Service.h"namespace DIP {class ServiceImpl : public Service{public:ServiceImpl(int a);~ServiceImpl() override;void Test() override;private:int m_a;}; }#endifServiceImpl.cpp
#include "ServiceImpl.h" #include <iostream>using namespace DIP;ServiceImpl::ServiceImpl(int a) : m_a(a) {std::cout << "In ServiceImpl, m_a = " << m_a << "." << std::endl; }ServiceImpl::~ServiceImpl() {std::cout << "In ~ServiceImpl, m_a = " << m_a << "." << std::endl; }void ServiceImpl::Test() {m_a++;std::cout << "In Test, m_a = " << m_a << "." << std::endl; } -
注入依赖:通过构造函数依赖注入,将实现
DIP::Service接口的对象传入,将具体实现传递给高层模块的接口指针或引用,从而对具体实现DIP::ServiceImpl解耦。main.cpp
#include "ServiceImpl.h" #include "Service.h" #include <memory>int main() {int a = 3;std::shared_ptr<DIP::Service> serviceImpl = std::make_shared<DIP::ServiceImpl>(a);serviceImpl->Test(); }在这种设计中,高层的
main函数依赖于抽象接口Service,而不是具体的实现类。这样只要继承了Service接口的实现类都可以被使用。这就是依赖倒置带来的灵活性和扩展性。
四、完整实现
-
在以上三点的基础上继续编写
CMakeLists.txt文件。# 设置项目名称和最低CMake版本 cmake_minimum_required(VERSION 3.10) set(ProjectName Service) project(${ProjectName})set(CMAKE_CXX_STANDARD 17) set(CMAKE_CXX_STANDARD_REQUIRED True)add_executable(${ProjectName} main.cpp ServiceImpl.cpp) -
此时代码结构如下。

-
命令行编译执行。
mkdir build cd build cmake .. make -j12 ./Service -
执行结果。
In ServiceImpl, m_a = 3. In Test, m_a = 4. In ~ServiceImpl, m_a = 4. -
可以看到
Service指针在不感知ServiceImpl具体实现的情况下,仅通过调用接口实现了和ServiceImpl实例相同的功能。
相关文章:
【设计模式】如何用C++实现依赖倒置
【设计模式】如何用C实现依赖倒置 一、什么是依赖倒置? 依赖倒置原则(Dependency Inversion Principle,DIP)是SOLID面向对象设计原则中的一项。它的核心思想是: 高层模块不应该依赖于低层模块,两者都应该…...
使用onnxruntime-web 运行yolov8-nano推理
ONNX(Open Neural Network Exchange)模型具有以下两个特点促成了我们可以使用onnxruntime-web 直接在web端上运行推理模型,为了让这个推理更直观,我选择了试验下yolov8 识别预览图片: 1. 跨平台兼容性 ONNX 是一种开…...
Gin框架html/vue前端使用hls.js播放/点播m3u8(hls)格式视频
说明 在web应用开发时遇到在线播放m3u8格式视频,由于m3u8是多分片视频,原生video标签无法直接播放,所以需要js对m3u8处理才能播放,网上有很多插件,这里我选择最近简单方法hls.js播放,引入一个js文件即可。…...
HarmonyOS 私仓搭建
1. HarmonyOS 私仓搭建 私仓搭建文档:https://developer.huawei.com/consumer/cn/doc/harmonyos-guides-V5/ide-ohpm-repo-quickstart-V5 发布共享包[https://developer.huawei.com/consumer/cn/doc/harmonyos-guides-V5/ide-har-publish-0000001597973129-V5]…...
Mybatis学习笔记(二)
八、多表联合查询 (一) 多表联合查询概述 在开发过程中单表查询不能满足项目需求分析功能,对于复杂业务来讲,关联的表有几张,甚至几十张并且表与表之间的关系相当复杂。为了能够实业复杂功能业务,就必须进行多表查询,…...
Google“Big Sleep“人工智能项目发现真实软件漏洞
据Google研究人员称,该公司的一个人工智能项目足够聪明,能够自行发现现实世界中的软件漏洞;Google的人工智能项目最近在开源数据库引擎 SQLite 中发现了一个之前未知的可利用漏洞。 该公司随后在正式软件发布之前报告了这一漏洞,这…...
npm入门教程5:package.json
一、package.json 文件的作用 依赖管理:列出项目所依赖的包(库)及其版本,便于其他开发者或自动化工具快速安装和更新这些依赖。元数据描述:提供项目的描述、作者、许可证等元信息,有助于项目的管理和维护。…...
docker-高级(待补图)
文章目录 数据卷(Volume)介绍查看方法删除方法绑定方法匿名绑定具名绑定Bind Mount 数据卷管理 网络bridge(桥接模式 默认)HOST(主机模式)Nonecontainer(指定一个容器进行关联网络共享)自定义(推荐)docker network 命令创建网络docker network create 实例展示-自定义实例展示-…...
Qt 文件目录操作
Qt 文件目录操作 QDir 类提供访问系统目录结构 QDir 类提供对目录结构及其内容的访问。QDir 用于操作路径名、访问有关路径和文件的信息以及操作底层文件系统。它还可以用于访问 Qt 的资源系统。 Qt 使用“/”作为通用目录分隔符,与“/”在 URL 中用作路径分隔符…...
Pandas 数据清洗
1.数据清洗定义 数据清洗是对一些没有用的数据进行处理的过程。很多数据集存在数据缺失、数据格式错误、错误数据或重复数据的情况,如果要使数据分析更加准确,就需要对这些没有用的数据进行处理。 2.清洗空值 DataFrame.dropna(axis0, howany, threshN…...
IO学习笔记
当前需求,希望进行游戏可以保存游戏进度,可以将游戏的进度保存到一个文本文件,每一次打完游戏更新文本内容,下一次打游戏读取游戏进度,这里就涉及到两个知识IO流和File的知识。 File类 概述 java.io.File 类是文件…...
汇编练习-1
1、要求 练习要求引自《汇编语言-第4版》实验10.3(P209页) -编程,将data段中的数据,以10进制的形式显示出来 data segment dw 123,12666,1,8,3,38 data ends 2、实现代码(可惜没找到csdn对8086汇编显示方式) assume cs:codedata segmentdw 16 dup(0) ;除…...
初识二叉树( 二)
初识二叉树 二 实现链式结构二叉树前中后序遍历遍历规则代码实现 结点个数以及高度等层序遍历判断是否为完全二叉树 实现链式结构二叉树 ⽤链表来表示⼀棵二叉树,即用链来指示元素的逻辑关系。通常的方法是链表中每个结点由三个域组成,数据域和左右指针…...
AcWing1077-cnblog
问题背景 给定一个树形结构的图,每个节点代表一个地点,每个节点有一个守卫的代价。我们希望以最低的代价在树的节点上放置守卫,使得整棵树的所有节点都被监控。可以通过三种方式覆盖一个节点: 由父节点监控。由子节点监控。自己…...
五、SpringBoot3实战(1)
一、SpringBoot3介绍 1.1 SpringBoot3简介 SpringBoot版本:3.0.5 https://docs.spring.io/spring-boot/docs/current/reference/html/getting-started.html#getting-started.introducing-spring-boot 到目前为止,你已经学习了多种配置Spring程序的方式…...
练习LabVIEW第三十三题
学习目标: 刚学了LabVIEW,在网上找了些题,练习一下LabVIEW,有不对不好不足的地方欢迎指正! 第三十三题: 用labview编写一个判断素数的程序 开始编写: LabVIEW判断素数,首先要搞…...
如何在服务器端对PDF和图像进行OCR处理
介绍 今天我想和大家分享一个我在研究技术资料时发现的很好玩的东西——Tesseract。这不仅仅是一个普通的库,而是一个用C语言编写的OCR神器,能够识别一大堆不同国家的语言。我一直在寻找能够处理各种文档的工具,而Tesseract就像是给了我一把…...
Windows 下实验视频降噪算法 MeshFlow 详细教程
MeshFlow视频降噪算法 Meshflow 视频降噪算法来自于 2017 年电子科技大学一篇高质量论文。 该论文提出了一个新的运动模型MeshFlow,它是一个空间平滑的稀疏运动场 (spatially smooth sparse motion field),其运动矢量 (motion vectors) 仅在网格顶点 (m…...
Python入门:如何正确的控制Python异步并发量(制并发量的关键技巧与易错点解析)
文章目录 📖 介绍 📖🏡 演示环境 🏡📒 异步并发量控制 📒📝 Python异步并发简介📝 为什么要限制并发量🎈 资源管理🎈 服务稳定性📝 新手容易犯的错误🎈 忽略并发量限制🎈 错误设置并发量📝 设置并发量要注意的事情🎈 了解任务类型🎈 考虑系统资…...
qt QCheckBox详解
QCheckBox 是 Qt 框架中的一个控件,用于创建复选框,允许用户进行选择和取消选择。它通常用于表单、设置界面和任何需要用户选择的场景。 QCheckBox继承自QAbstractButton类,因此继承了按钮的特性。它表示一个复选框,用户可以通过…...
【Axure高保真原型】引导弹窗
今天和大家中分享引导弹窗的原型模板,载入页面后,会显示引导弹窗,适用于引导用户使用页面,点击完成后,会显示下一个引导弹窗,直至最后一个引导弹窗完成后进入首页。具体效果可以点击下方视频观看或打开下方…...
Vue记事本应用实现教程
文章目录 1. 项目介绍2. 开发环境准备3. 设计应用界面4. 创建Vue实例和数据模型5. 实现记事本功能5.1 添加新记事项5.2 删除记事项5.3 清空所有记事 6. 添加样式7. 功能扩展:显示创建时间8. 功能扩展:记事项搜索9. 完整代码10. Vue知识点解析10.1 数据绑…...
shell脚本--常见案例
1、自动备份文件或目录 2、批量重命名文件 3、查找并删除指定名称的文件: 4、批量删除文件 5、查找并替换文件内容 6、批量创建文件 7、创建文件夹并移动文件 8、在文件夹中查找文件...
智慧工地云平台源码,基于微服务架构+Java+Spring Cloud +UniApp +MySql
智慧工地管理云平台系统,智慧工地全套源码,java版智慧工地源码,支持PC端、大屏端、移动端。 智慧工地聚焦建筑行业的市场需求,提供“平台网络终端”的整体解决方案,提供劳务管理、视频管理、智能监测、绿色施工、安全管…...
8k长序列建模,蛋白质语言模型Prot42仅利用目标蛋白序列即可生成高亲和力结合剂
蛋白质结合剂(如抗体、抑制肽)在疾病诊断、成像分析及靶向药物递送等关键场景中发挥着不可替代的作用。传统上,高特异性蛋白质结合剂的开发高度依赖噬菌体展示、定向进化等实验技术,但这类方法普遍面临资源消耗巨大、研发周期冗长…...
Java如何权衡是使用无序的数组还是有序的数组
在 Java 中,选择有序数组还是无序数组取决于具体场景的性能需求与操作特点。以下是关键权衡因素及决策指南: ⚖️ 核心权衡维度 维度有序数组无序数组查询性能二分查找 O(log n) ✅线性扫描 O(n) ❌插入/删除需移位维护顺序 O(n) ❌直接操作尾部 O(1) ✅内存开销与无序数组相…...
【位运算】消失的两个数字(hard)
消失的两个数字(hard) 题⽬描述:解法(位运算):Java 算法代码:更简便代码 题⽬链接:⾯试题 17.19. 消失的两个数字 题⽬描述: 给定⼀个数组,包含从 1 到 N 所有…...
dedecms 织梦自定义表单留言增加ajax验证码功能
增加ajax功能模块,用户不点击提交按钮,只要输入框失去焦点,就会提前提示验证码是否正确。 一,模板上增加验证码 <input name"vdcode"id"vdcode" placeholder"请输入验证码" type"text&quo…...
SpringBoot+uniapp 的 Champion 俱乐部微信小程序设计与实现,论文初版实现
摘要 本论文旨在设计并实现基于 SpringBoot 和 uniapp 的 Champion 俱乐部微信小程序,以满足俱乐部线上活动推广、会员管理、社交互动等需求。通过 SpringBoot 搭建后端服务,提供稳定高效的数据处理与业务逻辑支持;利用 uniapp 实现跨平台前…...
HBuilderX安装(uni-app和小程序开发)
下载HBuilderX 访问官方网站:https://www.dcloud.io/hbuilderx.html 根据您的操作系统选择合适版本: Windows版(推荐下载标准版) Windows系统安装步骤 运行安装程序: 双击下载的.exe安装文件 如果出现安全提示&…...
