依赖注入和控制反转的理解

理解一

当某个java对象(调用者/使用者)需要调用/使用另一个Java对象(调用者,即依赖对象,这里注意区分依赖于别人和被别人依赖的关系,被依赖就是自身被他人需要)时,在传统模式下。我们一般使用new被调用者的方式来创建对象。这种方式会导致代码的耦合性强,不易于代码后期的维护和升级。

依赖注入:

站在spring容器的角度去描述:spring容器负责将需要的对象注入(赋值)到调用者的成员变量。即为调用者注入了它依赖的实例。这就是依赖注入。

控制反转:

站在调用者角度去描述:原先我们是在调用者的代码中直接控制被调用者。类似于这样

下面展示一些 内联代码片

public class Car {
    private String name;//汽车的名字
    //Engine为我么自定义个的一个发动机类,这里我们汽车依赖于发动机这个 对象。
    //而站在发动机角度看:发动机被汽车所依赖,所以发动机是被依赖对象/被调用者
    private Engine v8 = new Engine();//调用者直接控制被依赖对象,耦合性太强。
}

而现在有了spring容器后,对象的实例不是由调用者自己去new创建,而是由spring容器帮我们完成。站在调用者的角度去看,原先自己控制对象的创建权交给了容器。控制权发生了反转。这就是控制反转(对象的创建权反转)

理解二:

IOC是Inversion of Control的缩写,多数书籍翻译成“控制反转”。

1996年,Michael Mattson在一篇有关探讨面向对象框架的文章中,首先提出了IOC 这个概念。对于面向对象设计及编程的基本思想,前面我们已经讲了很多了,不再赘述,简单来说就是把复杂系统分解成相互合作的对象,这些对象类通过封装以后,内部实现对外部是透明的,从而降低了解决问题的复杂度,而且可以灵活地被重用和扩展。

IOC理论提出的观点大体是这样的:借助于“第三方”实现具有依赖关系的对象之间的解耦。如下图:
在这里插入图片描述

大家看到了吧,由于引进了中间位置的“第三方”,也就是IOC容器,使得A、B、C、D这4个对象没有了耦合关系,齿轮之间的传动全部依靠“第三方”了,全部对象的控制权全部上缴给“第三方”IOC容器,所以,IOC容器成了整个系统的关键核心,它起到了一种类似“粘合剂”的作用,把系统中的所有对象粘合在一起发挥作用,如果没有这个“粘合剂”,对象与对象之间会彼此失去联系,这就是有人把IOC容器比喻成“粘合剂”的由来。

我们再来做个试验:把上图中间的IOC容器拿掉,然后再来看看这套系统:
在这里插入图片描述

我们现在看到的画面,就是我们要实现整个系统所需要完成的全部内容。这时候,A、B、C、D这4个对象之间已经没有了耦合关系,彼此毫无联系,这样的话,当你在实现A的时候,根本无须再去考虑B、C和D了,对象之间的依赖关系已经降低到了最低程度。所以,如果真能实现IOC容器,对于系统开发而言,这将是一件多么美好的事情,参与开发的每一成员只要实现自己的类就可以了,跟别人没有任何关系!

我们再来看看,控制反转(IOC)到底为什么要起这么个名字?我们来对比一下:

软件系统在没有引入IOC容器之前,如图1所示,对象A依赖于对象B,那么对象A在初始化或者运行到某一点的时候,自己必须主动去创建对象B或者使用已经创建的对象B。无论是创建还是使用对象B,控制权都在自己手上。

软件系统在引入IOC容器之后,这种情形就完全改变了,如图3所示,由于IOC容器的加入,对象A与对象B之间失去了直接联系,所以,当对象A运行到需要对象B的时候,IOC容器会主动创建一个对象B注入到对象A需要的地方。

通过前后的对比,我们不难看出来:对象A获得依赖对象B的过程,由主动行为变为了被动行为,控制权颠倒过来了,这就是“控制反转”这个名称的由来。

理解三:

依赖注入:他是spring框架核心ioc的具体实现
在编写程序时,通过控制反转,把对象的创建交给spring,但是代码
中不可能出现没有依赖的情况。
Ioc解耦只是降低他们的依赖关系,但不会消除。例如:
业务层仍会调用持久层的方法。
这种业务层和持久层的依赖关系,在使用spring之后,就让spring来维护了。
简单的说,就是坐等框架把持久层对象传入业务层,不不用我们自己去获取

Spring 能有效地组织J2EE应用各层的对象。不管是控制层的Action对象,还是业务层的Service对象,还是持久层的DAO对象,都可在Spring的 管理下有机地协调、运行。Spring将各层的对象以松耦合的方式组织在一起,Action对象无须关心Service对象的具体实现,Service对 象无须关心持久层对象的具体实现,各层对象的调用完全面向接口。当系统需要重构时,代码的改写量将大大减少。

上面所说的一切都得宜于Spring的核心机制,依赖注入依赖注入让bean与bean之间以配置文件组织在一起,而不是以硬编码的方式耦合在一起。理解依赖注入
依赖注入(Dependency Injection)和控制反转(Inversion of Control)是同一个概念。具体含义是:当某个角色(可能是一个Java实例,调用者)需要另一个角色(另一个Java实例,被调用者)的协助时,在 传统的程序设计过程中,通常由调用者来创建被调用者的实例。但在Spring里,创建被调用者的工作不再由调用者来完成,因此称为控制反转;创建被调用者 实例的工作通常由Spring容器来完成,然后注入调用者,因此也称为依赖注入。

不管是依赖注入,还是控制反转,都说明Spring采用动态、灵活的方式来管理各种对象。对象与对象之间的具体实现互相透明。在理解依赖注入之前,看如下这个问题在各种社会形态里如何解决:一个人(Java实例,调用者)需要一把斧子(Java实例,被调用者)。

(1)原始社会里,几乎没有社会分工。需要斧子的人(调用者)只能自己去磨一把斧子(被调用者)。对应的情形为:Java程序里的调用者自己创建被调用者。

(2)进入工业社会,工厂出现。斧子不再由普通人完成,而在工厂里被生产出来,此时需要斧子的人(调用者)找到工厂,购买斧子,无须关心斧子的制造过程。对应Java程序的简单工厂的设计模式。

(3)进入“按需分配”社会,需要斧子的人不需要找到工厂,坐在家里发出一个简单指令:需要斧子。斧子就自然出现在他面前。对应Spring的依赖注入。

第一种情况下,Java实例的调用者创建被调用的Java实例,必然要求被调用的Java类出现在调用者的代码里。无法实现二者之间的松耦合。

第二种情况下,调用者无须关心被调用者具体实现过程,只需要找到符合某种标准(接口)的实例,即可使用。此时调用的代码面向接口编程,可以让调用者和被调用者解耦,这也是工厂模式大量使用的原因。但调用者需要自己定位工厂,调用者与特定工厂耦合在一起。

第三种情况下,调用者无须自己定位工厂,程序运行到需要被调用者时,系统自动提供被调用者实例。事实上,调用者和被调用者都处于Spring的管理下,二者之间的依赖关系由Spring提供。

所谓依赖注入,是指程序运行过程中,如果需要调用另一个对象协助时,无须在代码中创建被调用者,而是依赖于外部的注入。Spring的依赖注入对调用者和被调用者几乎没有任何要求,完全支持对POJO之间依赖关系的管理。依赖注入通常有两种:

·设值注入。

·构造注入。

所谓依赖,举个例子说明,一个类Person,另一个类Car,如果Person的某个方法比如说drive,需要引用Car,则称Person类依赖于 Car类,延伸到对象,这种依赖关系依然成立,比如说Person类的对象boy依赖于Car类的对象toyota。再讲讲这个drive方法的实现,假定代码如下:
这其中的依赖关系,就导致了对象boy需要负责对象toyota的创建,甚至是整个生命周期的管理,而这样显然会带来耦合度高,不易维护等缺点,比如说要让这个男孩驾驶一辆Audi,则还需要修改类Person的代码。
因此在java的设计理论中就提出了一条非常著名的原则,依赖倒转原则(Dependence Inversion),其核心思想就是要将这种具体类之间的依赖,尽量转换成抽象依赖,也就是说类Person应该依赖于抽象类ICar,而不是具体的类 Car,这里java就大力推荐了抽象和接口的使用,至于抽象和接口之间的区别,任何一本JAVA书籍都有介绍,这里就不再说了。 这个依赖倒转原则在设计模式也体现得非常多,比如说工厂模式和构建模式,个人认为控制反转IoC,其实也可以认为是实现这个原则的一种设计模式。控制反转,其中的控制这个词一直不太理解是什么意思,不过控制反转的另外一种说法也就是依赖注入(dependence injection),个人觉得更易于理解。还是以上文的boy与toyota为例,其核心就是要将boy依赖的对象toyota注入到boy中去,而无需boy自己去引用toyota,这个注入的过程,通常是由一个控制程序来完成的,无需对象去关心,举例如下:

Public Person{

public void drive(){
Car toyota=new Car(“TOYOTA”);
toyota.挂档;
toyota.踩油门;
toyota.打方向;
}
}

  • 4
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值