依赖倒转原则:DIP
定义:
高层模块不应该依赖底层模块,两者都应该依赖其抽象;
抽象不应该依赖细节;
细节应该依赖抽象
解释描述:
核心是依赖于抽象, 在依赖之间定义一个抽象的接口使得高层模块调用接口,而底层模块实现接口的定义,以此来有效控制耦合关系,达到依赖于抽象的设计目标。
注意:接口设计的时候不应该为一个具体功能设计的,但具体编码实现是要依赖于某一接口的,接口是一个一对多的关系(一个接口多个实现)。
实例:
举一个“肥鹅”要练跆拳道的例子,“肥鹅”呢,首先这是一个朋友的外号,我们这里把他当作人看,就是说看成一个高层的模块,而练跆拳道这件事就把它看成底层模块。
在肥鹅只要做这一件事的时候,会很自然的用下面的代码来实现。
#include <iostream>
using namespace std;
class Taekwondo
{
public:
Taekwondo(){}
~Taekwondo(){}
public:
const std::string Goosetaekwondo()
{
return "a fat goose want to...";
}
};
class Goose
{
public:
Goose(){}
~Goose(){}
public:
void active(Taekwondo& taekwondo)
{
std::cout << taekwondo.Goosetaekwondo() << std::endl;
}
};
int main(int argc, char *argv[])
{
Taekwondo taekwondo;
Goose* goose = new Goose();
if(goose != nullptr)
{
goose->active(taekwondo);
}
return 0;
}
但是如果出现很多事情需要肥鹅去做的话,肥鹅要去打网球,肥鹅女朋友找他,肥鹅......,这时候就可以用依赖倒转原则
抽象出所有肥鹅需要做的事的父类接口
class IContent
{
public:
IContent(){}
virtual ~IContent(){}
public:
virtual const std::string GetContent() const = 0;
}
然后需要实现的类来继承这个父类接口:
class Taekwondo:public IContent
{
public:
virtual const std::string GetContent() const
{
return "a fat goose wang to ......";
}
};
class Girlfriend:public IContent
{
virtual const std::string GetContent() const
{
return "a fat goose also want to......";
}
};
......
这个肥鹅类就直接来调用父类接口
class Goose
{
public:
void active(IContent& readContent)
{
std::cout<< readContent.GetContent() << std::endl;
}
};
然后就是实现的话,就是肥鹅去调用这些实现类的对象就好了,会很方便。
int main(int argc, char *argv[])
{
Goose* goose = new Goose();
if(goose)
{
Taekwondo taekwondo;
goose->active(taekwondo);
...
}
delete goose;
goose = NULL;
return 0;
}
上述就实现了一个全部依赖抽象的原则,高层调用接口,底层实现依赖接口,就符合了这个依赖倒转原则。