设计模式六大原则之一:依赖倒置原则(DIP :Dependence Inversion Principle)

本文深入探讨了依赖倒置原则(DIP),阐述了其定义、由来、解决方案及优点。通过C++示例说明如何在实际编程中应用DIP,以减少类间的耦合性,提高系统的稳定性和代码的可维护性。DIP强调高层模块依赖抽象,而非具体实现,提倡面向接口编程,以接口或抽象类作为依赖的基础。
摘要由CSDN通过智能技术生成

设计模式六大原则之一:依赖倒置原则(DIP :Dependence Inversion Principle)

定义

高层模块不应该依赖低层模块,二者都应该依赖其抽象;
抽象不应该依赖细节;
细节应该依赖抽象。
也就是说高层模块,低层模块,细节都应该依赖抽象

1、C++中什么是依赖倒置原则?
依赖倒置原则定义:依赖于抽象(接口),不要依赖具体的实现(类),也就是针对接口编程。

2、依赖倒置原则的图解。
在这里插入图片描述
在这里插入图片描述

3、你需要知道C++中的一个重要特性:高内聚,低耦合。高内聚,低耦合。高内聚,低耦合。

由来

类A直接依赖类B,假如要将类B改为类C,则必须通过修改类A的代码来达成。
类A一般是高层模块,负责复杂的业务逻辑。
类B和类C是低层模块,负责基本的原子操作。
修改类A,会给程序带来不必要的风险。
在这里插入图片描述

解决方案

将类A修改为依赖接口I,类B和类C各自实现接口I,类A通过接口I间接与类B或者类C发生联系,则会大大降低修改类A的几率。
在这里插入图片描述

优点

依赖倒置原则可以减少类间的耦合性,提高系统的稳定,降低并行开发引起的风险,提高代码的可读性和可维护性。

思考

1.依赖倒置原则跟面向接口编程是什么关系?
依赖倒置原则的核心思想就是面向接口编程

2.什么是细节?什么是抽象?他们有什么区别?
所谓细节就是较为具体的东西,比如具体的类,就如上面的类B与类C,有具体的实现。

所谓抽象就是具有契约性、共同性、规范性的表达,比如上面的接口I。它表达了一种契约–你需要实现funcA和funcB才能被当成I来对待。

相对于细节的多变性,抽象的东西要稳定的多。
以上面的类ABC作为例子,B、C类都属于细节,如果A直接依赖B或者C,那么B或C的改动有可能就会影响到A的稳定性。同样的,A对B或者C的操作也有可能影响到B或C的稳定性。这些互相影响,其实来源于直接的依赖,导致B或C的细节暴露过多。而面对抽象的接口I,A只能操作funA和funcB,从而避免了不必要的暴露和风险。

以抽象为基础搭建起来的架构比以细节为基础搭建起来的架构要稳定的多。
稳定性表现在规范性、契约性、易修改性、扩展性、可维护性等。

注意点

分清细节与抽象
虽然依赖倒置原则有很大的好处,但也不是所有的类都需要有抽象一个接口去对应,要视情况而定。

变量的声明类型尽量是抽象类或接口
注意是尽量,而不是全部。

尽量不要覆写基类的方法
如果基类是一个抽象类,而这个方法已经实现了,子类尽量不要覆写。类间依赖的是抽象,覆写了抽象方法,对依赖的稳定性会有一定的影响。

继承要遵循里氏替换原则

示例

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

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

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

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

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

int main(int argc, char *argv[])
{
    Book book;
	Mother* mother = new Mother();
	if(mother != nullptr)
	{
		mother->readBook(book);   //妈妈给我讲故事,我乖乖睡觉觉.......
	}
	delete mother;
	mother = 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 Mother
{
public:
	void read(IReadContent& readContent)
	{
		std::cout<< readContent.GetContent() << std::endl;
	}
};

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

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

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

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

资料链接:
https://www.jianshu.com/p/bb1d5a0c65d6

https://blog.csdn.net/weixin_39951988/article/details/85704400?utm_medium=distribute.pc_relevant.none-task-blog-2%7Edefault%7EBlogCommendFromBaidu%7Edefault-6.no_search_link&depth_1-utm_source=distribute.pc_relevant.none-task-blog-2%7Edefault%7EBlogCommendFromBaidu%7Edefault-6.no_search_link

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值