以C/C++语法浅谈六大设计原则(一)——依赖倒置原则(Dependence Inversion Principle)

版权声明:版权所有,转载请注明出处 https://blog.csdn.net/weixin_39951988/article/details/85704400

一. 前言

众所周知,在软件开发过程中,我们的六大设计原则与二十三种设计模式可以说是我们开发的思想精髓。然而,网上或者书本大多数的资料都是以java、python等其他语言语法进行介绍与阐述,很少有以C/C++的语法进行深入介绍。鉴于此,本人以浅薄的见识对这些精妙的思想做以总结,方便我们在今后的工作、学习中进行查阅参考。本篇以设计六大原则之一的“依赖倒置原则进行讲起”。

二.依赖倒置原则

1. 定义
高层模块不应该依赖于底层模块,而应该依赖于抽象。抽象不应依赖于细节,细节应依赖于抽象。
2. 解决的问题
类A直接依赖类B,假如要将类A改为依赖类C,则必须通过修改类A的代码来达成。这种场景下,类A一般是高层模块,负责复杂的业务逻辑;类B和类C是低层模块,负责基本的原子操作;假如修改类A,会给程序带来不必要的风险。因此我们需要将依赖的方向进行重新规划,像下面这样:
在这里插入图片描述
我们将接口与实现相分离,应用与细节相分离,接口层提供我们业务层所需要的接口方法,实现层对接口的具体方法进行实现,高层业务逻辑不关心接口实现的具体细节,它只对接口进行调用,从而降低了类之间的耦合性,增加了代码的可读性,降低了后续维护的成本。

3.实例
我们了解了依赖倒置解决问题的具体方法,下面让我们以C/C++的编程视角来看看在具体的项目中我们该如何实现。
我们以经典的妈妈给我讲故事来看代码的具体实现:
首先我们定义一本故事书类,像这样:

 #include <iostream>
 
using namespace std;
class Book
{
public:
	Book(){}
	~Book(){}
public:
	const std::string GetBookText()
	{
		return "once upon a time......";  //很久很久以前......
	}
};

然后我们的妈妈类隆重登场,像这样:

class Monther
{
public:
	Monther(){}
	~Monther(){}
public:
	void readBook(Book& book)
	{
		std::cout << book.GetBookText() << std::endl;
	}
};

然后我们的妈妈开始给我们讲睡前故事,像这样:

int main(int argc, char *argv[])
{
    Book book;
	Monther* monther = new Monther();
	if(monther != nullptr)
	{
		monther->readBook(book);   //妈妈给我讲故事,我乖乖睡觉觉.......
	}
	delete monther;
	monther = NULL;
	return 0;
}

到此,妈妈故事讲完了,我也乖乖睡觉了,可是,可是,,,,突然有一天,我不想听故事了,我想听新闻,想听广播,还想听…阿欧,妈妈遇到这样的小孩也算是“前世修来的福”,可我们是孝顺的孩子呀,我们可以这样去设计我们的代码逻辑,注意了,真正的依赖倒置设计登场了,注意,注意,注意!!!
首先,我们抽象出一个所有读物的基类父接口,像这样:

class IReadContent 
{
public:
	IReadContent(){}
	virtual ~IReadContent(){}      //析构函数定义为virtual类型,保证派生类继承后析构时析构完全
public:
	virtual const std::string GetContent() const = 0;   //获取读物的具体内容
}

然后,我想听故事、想听新闻、还想听…嗯,,,,,让故事书、报纸,,,,继承这个读物类,像这样:

//《童话镇》  /*美剧,挺好看的一部通话故事剧,感兴趣可以去看看,,,,*/
class StoryBook:public IReadContent     //故事书类
{
public:
	virtual const std::string GetContent() const
	{
		return "很久很久以前,白雪公主与小矮人在魔法森林里智斗巫后......";
	}
};
//报纸类
class NewsPager:public IReadContent
{
	virtual const std::string GetContent() const
	{
		return "报纸上说,白雪公主与小矮人在童话镇幸福的生活着......";
	}
};

我们的妈妈又一次隆重登场了,阿欧,为什么要说“又”?这次的妈妈可是很厉害的,不信你看:

class Monther
{
public:
	void read(IReadContent& readContent)
	{
		std::cout<< readContent.GetContent() << std::endl;
	}
};

又到妈妈开始讲故事的时刻了,噢不,妈妈啥都能讲喽,且看下面分解:

int main(int argc, char *argv[])
{
	Monther* monther = new Monther();    //定义一个厉害的妈妈
	if(monther)
	{
		StoryBook storyBook;            //我想听故事
		monther->read(storyBook);     //给你讲故事

		NewsPager newsPager;        //我想听新闻
		monther->read(newsPager);   //给你说新闻

       //...                     //我想听...               
       //...                    //给你说...
       
		//......                   //我想听....
		//.......                  //你咋不上天.......
	}
	
	delete monther;
	monther = NULL;
	return 0;
}

至此,妈妈故事讲完了,我开始讲依赖倒置的故事了,嗯,妈妈是顶级的业务逻辑层(类Monther),接口层当然是我们的中间枢纽读物类接口(类IReadContent),细节实现层当人不让是我们的几个细节实现类(StoryBook、NewsPager 、等等),在回过头看看我们的定义:**“高层模块不应该依赖于底层模块,而应该依赖于抽象。抽象不应依赖于细节,细节应依赖于抽象。”**要是没有理解,建议从头再听一次妈妈讲故事,要是还没懂,嗯,来找我吧,我慢慢跟你讲妈妈讲故事:“很久很久以前…”

三.总结

善始善终吧,简单做个总结。
1.优点:

说明 简述
减少类之间的耦合 松耦合
提高系统的稳定性 稳定性
提高代码的可读性 可读性

2.本质
通过 抽象 即 接口或者抽象类, 使 各个类 和 模块实现彼此独立, 实现模块间 松耦合;

四.后续

程序的灵魂是思想,程序的思想精髓是设计原则与设计模式,后续会不断以C/C++的语法视角对设计原则与设计模式进行阐述。由于本人水平有限,文中有不足之处希望大家能及时指正。 后面有时间我会继续更新有关编程方面的知识,若有更好的想法和需求及时与我取得联系,相互学习,共同进步。

猜你喜欢

转载自blog.csdn.net/weixin_39951988/article/details/85704400