C++通透讲解设计模式:依赖倒转(1)

devtools/2025/1/19 20:55:33/

依赖倒转

这是我认为的SOLID里面最重要的一个原则,当你掌握这种设计方式之后,会让别人在调用你的代码时爽很多。

C++20设计模式这本书中,依赖倒转写的很抽象。我这里将他的概念列出:

  1. 高层模块不应该依赖底层模块,它们都应该依赖抽象接口。
  2. 抽象接口不应该依赖细节,细节应该依赖抽象接口。

看到这两句话就觉得很抽象,对吧?

其实我总结出一个规律描述上面的关系:

类与类之间的关联行为应当由一个或者多个抽象管理和约束(我们最后再解释这句话)

废话不多说,上例子:

首先有个需求,我们现在要实现一个人接收电子邮件或者qq信息的场景,正常来说你可能会这样设计:

  1. 电子邮件和QQ还有人,三个对象本身都应有个类
  2. 邮件和QQ作为单独的一个对象,应该有一个方法getinfo获取他们的信息
  3. 而人作为对象,应该有执行这个getinfo的能力。

根据上面的逻辑,我们应该如下设计:


class Email {
public:void getInfo() {cout << "Email getInfo" << endl;}
};class QQ {
public:void getInfo() {cout << "QQ getInfo" << endl;}
};class Person {
public:void receive(Email& email) {email.getInfo();}void receive(QQ& qq) {qq.getInfo();}
};

看起来很不错!!写的代码也很整齐!没有学习设计模式之前我也是这样认为的。

但是我们忽略了一个问题:

  • 高层与低层之间的依赖关系

这会造成什么呢?

如果某一天,你不再负责维护这个项目,而是转而去做别的。这个项目交给一个其他人来维护。

此时正好有个需求是——添加一种新的软件叫做kk语音,那新来的那个家伙是不是就要开始写代码了?

此时,他也写了一个函数叫做recv_info

class QQ {
private:std::string info;
public:std::string recv_info() {return "recv_info" + info;}
};

之后这个人又走了,又来一个新人…

长此以往,由于代码变得很多,新的程序员需要将经历放在实现功能上时往往就会忽略整个项目的结构,加上没有对应的接口来进行规范,就出现一种方法类乱设计的情况。

知道某一天来了一个人,遇到主函数逻辑需要大改的情况,调用这个方法时发现什么呢?有的命名为getinfo有的命名为recv_info有的方法是返回值传参,有的是传出参数传参…

当然,现实情况不一定是这样,上面的例子是一种夸张的比喻(但是不是说没人这样写)。

最正确的方法应该是什么呢?

将这个方法设计成抽象类(抽象接口),让底层和高层的实例类(也被称为细节)都去依赖它。

// 依赖倒转原则
class IReceiver {
public:	virtual ~IReceiver() = default;virtual void getInfo() = 0;
};class Email : public IReceiver {
public:void getInfo() override {cout << "Email getInfo" << endl;}
};class QQ : public IReceiver {	
public:void getInfo() override {cout << "qq getInfo" << endl;}
};class Person {
public:// 里氏替换原则void receive(IReceiver& receiver) {receiver.getInfo();}
};

这样写的话,后来的人再添加功能时,就会优先注意到IReceiver这个接口,从而根据这个接口来写对应的函数,如果接口的返回值不能满足它,它会额外设计一个分离开的接口,促使下一个人遵守另一条设计原则——接口隔离原则。

总而言之,返回我一开始总结的那句话:会发现高层和底层模块之间的依赖就是类与类之间的关联行为(getinfo)应当由一个或多个抽象管理和约束(设计成接口后,方便维护)

这就是依赖倒转原则。

当然,更先进的做法其实还有一种方法,叫做依赖注入,下次有机会再讲!


http://www.ppmy.cn/devtools/151911.html

相关文章

HNU人工智能课程总结与反思

HNU人工智能这门课教材用的是101计划的《人工智能引论》&#xff0c;浙江大学吴飞教授编的。个人认为&#xff0c;教材写的挺好&#xff0c;但是把人工智能这一领域的东西放在一本书里&#xff0c;用32个课时讲完还是太过于仓促。不过&#xff0c;对于我这个上课之前对人工智能…

Bootstrap 下拉菜单

Bootstrap 下拉菜单 Bootstrap 是一个流行的前端框架&#xff0c;它提供了许多预构建的组件&#xff0c;其中之一就是下拉菜单。下拉菜单是一个交互式元素&#xff0c;允许用户从一系列选项中选择一个。在本篇文章中&#xff0c;我们将详细介绍如何在 Bootstrap 中创建和使用下…

【protobuf】Windows与Linux下的安装详解

文章目录 一、Windows下的安装二、Linux下的安装1. 下载protobuf2. 安装protobuf 一、Windows下的安装 ​ 编译器下载地址&#xff1a;https://github.com/protocolbuffers/protobuf/releases ​ 下载之后将压缩包解压到本地目录下。解压后的文件内包含 bin、include 文件&a…

IDEA运行测试函数@Test注解旁边没有运行按钮

如图我想直接运行 testSaveShop 函数进行测试&#xff0c;但是旁边没有运行按钮。 解决办法&#xff1a;测试类需要加上public&#xff0c;系统才能识别到并调用运行。 位置如下&#xff0c;在类和方法都加上 public &#xff0c;然后就会出现运行按钮&#xff1a; 但是如果点…

2024年博客之星年度评选—创作影响力评审入围名单公布

2024年博客之星活动地址https://www.csdn.net/blogstar2024 TOP 300 榜单排名 用户昵称博客主页 身份 认证 评分 原创 博文 评分 平均 质量分评分 互动数据评分 总分排名三掌柜666三掌柜666-CSDN博客1001002001005001wkd_007wkd_007-CSDN博客1001002001005002栗筝ihttps:/…

算法日记4:796. 子矩阵的和(二维前缀和)

题目链接&#xff1a;Acwing796. 子矩阵的和 一、题目 二、解题思路&#xff1a; 让我们来分解问题 2.1法一&#xff1a;暴力0(n2) 首先对于这个题目&#xff0c;我们最先想到的是暴力解法即两层for循环即可实现程序&#xff0c;但是此时我们的程序就过于复杂&#xff0c;因…

CUDA C 编程入门学习记录

这是本人21年读书时学习CUDA基础知识保留的一些笔记&#xff0c;学习时的内容出处和图片来源不记得了&#xff0c;仅作为个人记录&#xff01; CUDA编程 host:主机端CPU device:设备端GPU kernels&#xff1a;核函数 global:定义一个kernel函数 入口函数&#xff0c;CPU调用&…

华为EulerOS 学习,是否要先 RHCE?

华为EulerOS 作为一款具有广阔前景的操作系统&#xff0c;吸引了众多有志于在 Linux 领域深耕的人士的目光。其中&#xff0c;不少人心中都有一个疑问&#xff1a;学习华为EulerOS&#xff0c;是否需要先拿下 RHCE 认证呢&#xff1f; 从个人多年在 IT 行业一线的经验来看&…