首页 > 代码库 > 依赖反转(Dependency inversion principle)和控制反转(Inversion of Control)

依赖反转(Dependency inversion principle)和控制反转(Inversion of Control)

       有两个对象A和B,A some B  是A依赖于B,当B some A的时候是B依赖于A这就叫依赖反转;

这种依赖关系如果让程序员自己控制(new 对象),就会出现高耦合,控制反转(依赖注入)就是让这种依赖关系由第三方管理(eg:spring)而不是程序员自己管理。


名词解释

依赖:一种模型元素之间的关系的描述。例如类A调用了类B,那么我们说类A依赖于类B。

耦合:一种模型元素之间的关系的描述。例如类A调用了类B或类B调用了类A,那么我们说类A与类B有耦合关系。

耦合度:模型元素之间的依赖程度的量化描述。

控制:一种模型元素之间的关系的描述。例如类A调用了类B,那么我们说类A控制类B。

绪论

架构设计的对象一般是类库、框架和应用程序。其工作任务除了类库、框架、应用程序各个模块(类)之间的关系设计之外,还包括类库、框架和应用程序三者之间关系的设计。而依赖倒置、控制反转、依赖注入正是常用的一类设计模式。

依赖倒置、控制反转、依赖注入三者含义和目标基本一致,即通过抽象接口解耦和消除依赖关系。

依赖倒置

从字面理解依赖倒置往往不知所云,通过了解其历史渊源可以很好的消除这种误解。在面向结构编程时代,架构设计师往往采用自上而下的设计模式,先设计上层模块,再设计下层模块,如此层层分解,导致上层模块严重依赖于下层模块,下层模块的一点变化都会导致上层地震。到了面向对象编程时代,架构设计师使用对象进行设计,通过抽象接口解耦各层之间的依赖关系,为了与面向结构的设计模式区分开,同时体现面向对象的优势,也为了哗众取宠,就给这种新的设计模式起了个依赖倒置的名称。

依赖倒置的核心思想是依赖于抽象。

依赖倒置的原则是上层模块不依赖于下层模块,而是依赖于一套抽象接口,上层模块调用接口,下层模块实现接口。以类库和应用程序为例,我们把应用程序需要调用的功能抽象为一组接口,然后由类库实现这组接口,那么应用程序就可以使用任意实现了该接口的类库,从而和类库解耦。

控制反转

控制反转的来历与依赖倒置相似,以前设计应用程序,虽然会引用类库,但一切都在应用程序的控制之中。后来根据应用程序的不同场景,人们设计了相应的框架,有了框架之后,再设计应用程序时,就变成了为框架增加自定义行为的设计,控制权转到了框架手里,因此说控制权反转了。

控制反转是依赖倒置的一种具体实现,强调的是控制流程的依赖倒置,是框架设计的必用模式。框架基于依赖倒置模式设计:对于框架中不确定的部分,框架抽象出一组接口,并依赖于这组接口进行实现,应用程序实现这组接口。

依赖注入

依赖注入也是依赖倒置的一种具体实现,是类库设计的一种常用模式。类库中的类基于依赖模式设计:某类依赖于接口,而不是具体的实现,由调用者在调用时传入这些接口的具体实现类。

.Net中广泛使用此模式,比如StreamReader类,当使用StreamReader时,需要实例化一个Stream或其派生类,传给StreamReader的构造函数,然后方能使用该类的方法。


弊病

依赖倒置的基础是假设抽象是稳定的。对于我们已经了解的事物,当然可以实现很好的抽象,但对于尚未认识清楚的事物,比如用户需求,就很难保证这个抽象的稳定性。因此一旦这个抽象稳定的假设不成立,那么依赖倒置不但不能发挥优势,反倒可能成为包袱。