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)应当由一个或多个抽象管理和约束(设计成接口后,方便维护)

这就是依赖倒转原则。

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

相关推荐
敲上瘾1 分钟前
MySQL数据类型
数据库·c++·mysql·数据库开发·数据库架构
oliveira-time1 小时前
Java 1.8(也称为Java 8)
java·开发语言
小陶来咯1 小时前
【高级IO】多路转接之单线程Reactor
服务器·网络·数据库·c++
钰爱&5 小时前
【Linux】POSIX 线程信号量与互斥锁▲
java·开发语言·jvm
yt948326 小时前
Matlab实现绘制任意自由曲线
开发语言·matlab
C++实习生7 小时前
powerbuilder9.0中文版
c语言·c++
oioihoii7 小时前
C++23 std::generator:用于范围的同步协程生成器 (P2502R2, P2787R0)
开发语言·c++·c++23
免檒7 小时前
go基于redis+jwt进行用户认证和权限控制
开发语言·redis·golang
没有梦想的咸鱼185-1037-16638 小时前
全球森林数据如何分析?基于R语言森林生态系统结构、功能与稳定性分析与可视化
开发语言·随机森林·数据分析·r语言
Your易元8 小时前
设计模式-迭代器模式
java·开发语言