目录
如果新手开始没在搞清楚什么是IOC反转控制)和DI(依赖)注入,越学到后面越懵,所以前提概念一定要学清楚。
我将在后一章详细说下,现在是概说
一、什么是IOC、DI
根据百度百科IOC概念:
控制反转(Inversion of Control,缩写为IoC),是面向对象编程中的一种设计原则,可以用来减低计算机代码之间的耦合度。其中最常见的方式叫做依赖注入(Dependency Injection,简称DI),还有一种方式叫“依赖查找”(Dependency Lookup)。通过控制反转,对象在被创建的时候,由一个调控系统内所有对象的外界实体将其所依赖的对象的引用传递给它。也可以说,依赖被注入到对象中。
从上面可以看出,IOC并不是一种技术,而是一种设计思想、设计原则。在Java开发中,Ioc意味着将你设计好的对象交给容器控制,而不是传统的在你的对象内部直接控制。
既然IOC是思想的话,那么得有实现技术的手段啊,当思想没落地,那是画饼!所以上面介绍了DI和DL两种技术实现手段。
在spring中实现IOC设计思想是通过DI(依赖注入)的技术手段实现的。
所谓依赖注入,就是由IOC容器在运行期间,动态地将某种依赖关系注入到对象之中。
二、依赖注入的好处
spring的作用是减低耦合,从编译器降低,例如不直接通过new方式 而是通过工厂方式获取对象。
依赖注解的好处主要有2个:
1.解偶
2.易于测试
可能直接写2个不好理解,可以看一下后面的“附录一”,也可以看一下“依赖注入和单元测试”这篇文章,文章中提到一个概念
当一个类A依赖于另外一个类B的时候,类B的实现直接在类A中设置,我们说A紧耦合于B。
PS:软件设计中一般是推荐 高内聚低耦合,其中 降低耦合度的方法 提到:
最后当然就是避免直接操作或调用其它模块或类(内容耦合);如果模块间必须存在耦合,原则上尽量使用数据耦合,少用控制耦合,限制公共耦合的范围,避免使用内容耦合。
附录一、 IOC好处
好处就是实现松偶合(解偶)和易于测试。
如果不懂什么是“解耦”,看了这个例子你就明白了):
1.从下面的图可以看出,相互啮合的A、B、C、D四个齿轮组成一个齿轮组,用来完成某项任务。但是,如果有一个齿轮出了问题,就很有可能影响整个齿轮组的正常运转。
我们可以把齿轮组中的齿轮之间的关系,类比为软件系统中对象之间的耦合关系。对象之间的耦合是无法避免的,因为这是协同合作的基础。但随着软件的规模越来越来,比如一些工业级的软件,那么对象之间的依赖关系也会相当复杂,经常会出现对象之间的多重依赖性关系。耦合度过高,结果就会导致“牵一发而动全身”的情形。所以,为了实现对象之间的“解耦”,提出了IoC理论。
2.引入IoC容器,充当“黏合剂”的作用,使得A、B、C、D四个齿轮(对象)没有了解耦关系,这样程序员就能够更好地分工开发各个模块了
这里使用计算机和u盘的例子来简单说明:
1.方便解耦,简化开发:计算机和u盘之间没有相关性,无论哪个出现问题都不会影响另一方。而且,因为这两种组件之间的无耦合,所以生成计算机的厂商和生成u盘的厂商可以不同。这样的话就能够更好的分工开发了。
2.易于测试:因为计算机和u盘之间的无关性,所以非常便于单元测试,分开调试和诊断。这符合spring一直贯彻的“好的设计优于具体实现,代码应易于测试”的理念。
附录二、spring的依赖注入如何降低了耦合
依赖注入:程序运行过程中,如需另一个对象协作(调用它的方法、访问他的属性时),无须在代码中创建被调用者,而是依赖于外部容器的注入
看过一些比较好的回答
1.一个人(Java实例,调用者)需要一把斧子(Java实例,被调用者)
在原始社会里,几乎没有社会分工;需要斧子的人(调用者)只能自己去磨一把斧子(被调用者);对应情形为:Java程序里的调用者自己创建被调用者,通常采用new关键字调用构造器创建一个被调用者
进入工业社会,工厂出现了,斧子不再由普通人完成,而在工厂里被生产出来,此时需要斧子的人(调用者)找到工厂,购买斧子,无须关心斧子的制造过程;对应简单工厂设计模式,调用者只需定位工厂,无须管理被调用者的具体实现
进入“共产主义”社会,需要斧子的人甚至无须定位工厂,“坐等”社会提供即可;调用者无须关心被调用者的实现,无须理会工厂,等待Spring依赖注入
总之依赖注入的意思是你需要的东西不是由你创建的,而是第三方,或者说容器提供给你的。这样的设计符合正交性,即所谓的松耦合。
2.依赖注入是调用者仅通过声明某个组件就可以获得组件的控制权,而对该组件的依赖关系管理、查找、加载由外部完成。
3.依赖注入就是你不用关心对象的生命周期,什么时候被创建,什么时候销毁,只需直接使用即可,对象的生命周期由提供依赖注入的框架来管理。
一个简单的例子如下:
public class example1 implement example1Impl{
private example2 exam2;
public example1(){
exam2=new exam2();
}
public void xxx(){
exam2.xxx();
}
}
采用注入的方式(构造器注入):
public class example1 implement example1Impl{
private example2 exam2;
public example1(exam2){
this.exam2=exam2;
}
public void xxx(){
exam2.xxx();
}
}
如何理解第二个比第一个降低了example1和example2类之间的耦合度呢?
Spring可以通过注解和xml配置文件来体现依赖注入,example1不需要自行创建example2的对象,容器通过配置文件设置bean的property属性,这样代码中的依赖关系转移到了配置文件中了。