浅尝 依赖倒置&控制反转&依赖注入

要想知道这三者的来历,我们先要知道这两个概念:

1.依赖:依赖描述了两个模型元素之间的关系,在类图上,依赖表明客户类的操作会调用服务器类的操作

2.耦合:如果改变程序的一个模块要求另一个模块同时发生变化,就认为这两个模块发生了耦合。

 

从上面的定义我们可以看出:如果模块A调用模块B提供的方法,或访问模块B中的某些数据成员,我们就认为模块A依赖于模块B,也可以说是模块A控制模块B,模块A和模块B之间发生了耦合。

 

那么依赖对于我们的程序设计来说,到底会有怎样的影响呢?

 

由于人类的理解力有限,大多数人难以理解和把握过于复杂的系统。把软件系统划分成多个模块,可以有效控制模块的复杂度,使每个模块都易于理解和维护。但在这种情况下,模块之间就必须以某种方式交换信息,也就是必然要发生某种耦合关系。如果某个模块和其它模块没有任何关联(哪怕只是潜在的或隐含的依赖关系),我们就几乎可以断定,该模块不属于此软件系统,应该从系统中剔除。如果所有模块之间都没有任何耦合关系,其结果必然是:整个软件不过是多个互不相干的系统的简单堆积,对每个系统而言,所有功能还是要在一个模块中实现,这等于没有做任何模块的分解。

 

因此,模块之间必定会有这样或那样的依赖关系,永远不要幻想消除所有依赖。但是,过强的耦合关系(如一个模块的变化会造成一个或多个其他模块也同时发生变化的依赖关系)会对软件系统的质量造成很大的危害。特别是当需求发生变化时,代码的维护成本将非常高。所以,我们必须想尽办法来控制和消解不必要的耦合,特别是那种会导致其它模块发生不可控变化的关系。依赖倒置、控制反转、依赖注入等原则就是人们在和依赖关系进行艰苦卓绝的斗争过程中不断产生和发展起来的。

 

依赖倒置(Dependence inversion

Robert Matin是这样描述依赖倒置原则的:

1.上层模块不应该依赖于下层模块,他们共同依赖于一个抽象;

2.抽象不能依赖于具象,具象依赖于抽象

其含义是:为了消除两个模块间的依赖关系,一概在两个模块之间顶一个抽象接口,上层模块调用抽象接口定义的函数,下层模块实现该接口。以类库和应用程序为例,我们把应用程序需要调用的功能抽象为一组接口,然后由类库实现这组接口,那么应用程序就可以使用任意实现了该接口的类库,从而和类库解耦。

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

 

控制反转

控制反转

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

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

依赖注入

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

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


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值