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

依赖倒转

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

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

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

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

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

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

废话不多说,上例子:

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

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

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

cpp 复制代码
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:

cpp 复制代码
class QQ {
private:
	std::string info;
public:
	std::string recv_info() {
		return "recv_info" + info;
	}
};

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

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

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

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

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

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

cpp 复制代码
// 依赖倒转原则
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)应当由一个或多个抽象管理和约束(设计成接口后,方便维护)

这就是依赖倒转原则。

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

相关推荐
来让爷抱一个10 分钟前
Python 异步里混用同步库,事件循环被卡住的全过程
开发语言·python
2601_967979122 小时前
设计模式 - 访问者模式
设计模式·访问者模式·应用场景·对象结构·操作分离
十二2 小时前
【洛谷题解】P1083 [NOIP 2012 提高组] 借教室(二分答案 + 差分)
数据结构·c++·算法·蓝桥杯
心祭丫丫3 小时前
【每天一个 Python 小案例17】Python 实现通讯录
开发语言·人工智能·笔记·python·学习
露天赏雪3 小时前
第3篇:Sentinel熔断降级实战:大模型接口抖动时的服务兜底方案
java·开发语言·人工智能·spring boot·spring·servlet·sentinel
D e re k ZH4 小时前
C++ 从零入门(一):基础语法与程序结构
数据结构·c++·算法
yeccheng6 小时前
MySQL 索引超详解:从底层 B+ 树到面试高频考点
java·开发语言·jvm·mysql·面试
联犀6 小时前
纯 Go 的 CAD 开源库 go-cad:直接解析 DWG/DXF,现在也能导出 PDF
开发语言·golang·pdf
zjxtxdy6 小时前
C++面向对象程序开发-类与对象
开发语言·c++
東隅已逝,桑榆非晚8 小时前
算法6. 双指针法-查找总价格为目标的两个商品
c++·学习·算法