首页 > 代码库 > Ioc与DI

Ioc与DI

关于 IOC 和 DI 的理解
IOC:Inversion of Control 控制反转
DI:Dependency Injection 依赖注入
控制反转,从字面意思来看,就是控制权又被动变主动,最后又变回被动。
举个例子:
你的主管要求你做一件事情,这个时候就存在这么几个过程,
主管命令你做事情(这个时候主动权在主管,你是被动的)
你接到命令做事情(这个时候主题是你,你是主动的,控制权在你手里)
你完成事情(这个时候主题依然是你,控制权在你手里)
报告主管做完事情(主动权又叫交到主管手里了)
上面的整个过程就完成了一次 IOC,从上面可以看出,IOC 的基本思想是控制权
的转换过程。
举个代码的例子:
假如有 Class A, Class B,在 A 内部会初始化一个 B,调用 B 的一个方法 DoMethod
public  Class  B
{
public  void  DoMethod()
{
//  do  somthing;
}
}
public  Class  A
{
public  void  Excute()
{
B  b  =  new  B();
b.DoMethod();
}
}
假如在 Main 函数中如下执行:
A  a  =  new  A();
a.Excute(); 
从这两行代码来看,事实上也存在一个 IOC 的过程,a——>b——>a,理解的关
键点就在在 A 的内部调用 Excute 的时候,方法 b.DoMethod 的执行。
理解了 IOC,我们再看一下 DI。
从上面 A 调用 B 我们可以看出,在初始化一个 A 的实例时,也必须实例化一个 B,
也就是说如果没有 B 或者 B 出了问题,A 就无法实例化,这就产生了一种依赖,
就是 A 依赖 B,这种依赖从设计的角度来说就是耦合,显然它是无法满足高内聚
低耦合的要求的。这个时候就需要解耦,当然解耦有很多种方法,而 DI 就是其
中一种。不管任何一种解耦方法,都不是说使 A 和 B 完全没有关系,而是把这
种关系的实现变得隐晦,不那么直接,但是又很容易实现,而且易于扩展,不
像上面的代码那样,直接 new 一个 B 出来。
那为什么我们总是把 IOC 和 DI 联系到一起呢?是因为 DI 的基本思想就是 IOC,
而体现 IOC 思想的方法还有另外一个,那就是 Service Locator,这个方法好
像涉及到的很少。
DI,依赖注入,从字面意思就可以看出,依赖是通过外接注入的方式来实现的。
这就实现了解耦,而 DI 的方式通常有三种,
构造器注入
属性设置器注入
接口注入(我感觉接口注入是同时存在于上两种注入方式的,而不应该独立
出来)
以上的阐述只是为了先让我们能对 IOC 和 DI 有一个感性的理解,那么 IOC 真正
解决的问题是什么呢?
我们讲了那么多主动被动的问题,那我们是从什么视角来看待这个问题的呢?
所谓为什么你是主动,而我不是主动呢?这就需要一个参照物,那这个参照物
是什么呢?就是容器,在容器中来体现主动和被动。
用白话来讲,就是由容器控制程序之间的关系,而非传统实现中,由程序代码
直接操控。这也就是所谓“控制反转”的概念所在:控制权由应用代码中转到
了外部容器,控制权的转移,是所谓“反转”,这是通常对 IOC 的一个解释。
从容器的角度来看主动和被动,和由容器来控制程序之间的关系,应该是相通
的,是一个意思。
IOC 要解决的就是程序之间调用的一个问题,它应该是一个思想层面的东西,是
一个中心,就像一支乐队的指挥,而程序就是乐器,通过指挥来协调各种乐器,
来演奏出美好的音乐来。
-------------我是华丽丽的分割线,以下为引用--------------------
IOC 的深刻理解 
IoC 是什么?Inversion of Control,即反转控制,或许说为依赖注入更为合适。
IoC 就是 IoC,不是什么技术,与 GoF 一样,是一种设计模式。
Interface Driven Design 接口驱动,接口驱动有很多好处,可以提供不同
灵活的子类实现,增加代码稳定和健壮性等等,但是接口一定是需要实现的,
也就是如下语句迟早要执行:AInterface a = new AInterfaceImp(); 这样一
来,耦合关系就产生了,如:
Class A{
AInterface a;
A(){}
aMethod(){
a = new AInterfaceImp();
}
}
ClassA 与 AInterfaceImp 就是依赖关系,如果想使用 AInterface 的另外一个实
现就需要更改代码了。当然我们可以建立一个 Factory 来根据条件生成想要的
AInterface 的具体实现,即:
InterfaceImplFactory{
AInterface create(Object condition){
if(condition = condA){
return new AInterfaceImpA();
}elseif(condition = condB){
return new AInterfaceImpB();
}else{
return new AInterfaceImp();
}
}
}
表面上是在一定程度上缓解了以上问题,但实质上这种代码耦合并没有改变。
通过 IoC 模式可以彻底解决这种耦合,它把耦合从代码中移出去,放到统一的
XML 文件中,通过一个容器在需要的时候把这个依赖关系形成,即把需要的接口
实现注入到需要它的类中,这可能就是“依赖注入”说法的来源了。
IOC 模式,系统中通过引入实现了 IOC 模式的 IOC 容器,即可由 IOC 容器来
管理对象的生命周期、依赖关系等,从而使得应用程序的配置和依赖性规范与
实际的应用程序代码分开。其中一个特点就是通过文本的配件文件进行应用程
序组件间相互关系的配置,而不用重新修改并编译具体的代码。
当前比较知名的 IOC 容器有:Pico Container、Avalon 、Spring、JBoss、
HiveMind、EJB 等。
在上面的几个 IOC 容器中,轻量级的有 Pico Container、 Avalon、 Spring、
HiveMind 等,超重量级的有 EJB,而半轻半重的有容器有 JBoss,Jdon 等。
可以把 IoC 模式看做是工厂模式的升华,可以把 IoC 看作是一个大工厂,
只不过这个大工厂里要生成的对象都是在 XML 文件中给出定义的,然后利用 Java 
的“反射”编程,根据 XML 中给出的类名生成相应的对象。从实现来看,IoC 是
把以前在工厂方法里写死的对象生成代码,改变为由 XML 文件来定义,也就是
把工厂和对象生成这两者独立分隔开来,目的就是提高灵活性和可维护性。
IoC 中最基本的 Java 技术就是“反射”编程。反射又是一个生涩的名词,
通俗的说反射就是根据给出的类名(字符串)来生成对象。这种编程方式可以
让对象在生成时才决定要生成哪一种对象。反射的应用是很广泛的,象
Hibernate、String 中都是用“反射”做为最基本的技术手段。
在过去,反射编程方式相对于正常的对象生成方式要慢 10 几倍,这也许也
是当时为什么反射技术没有普通应用开来的原因。但经 SUN 改良优化后,反射
方式生成对象和通常对象生成方式,速度已经相差不大了(但依然有一倍以上
的差距)。
IoC 最大的好处是什么?因为把对象生成放在了 XML 里定义,所以当我们需
要换一个实现子类将会变成很简单(一般这样的对象都是现实于某种接口的),
只要修改 XML 就可以了,这样我们甚至可以实现对象的热插拨(有点象 USB 接
口和 SCIS 硬盘了)。
IoC 最大的缺点是什么?(1)生成一个对象的步骤变复杂了(其实上操作
上还是挺简单的),对于不习惯这种方式的人,会觉得有些别扭和不直观。(2)
对象生成因为是使用反射编程,在效率上有些损耗。但相对于 IoC 提高的维护
性和灵活性来说,这点损耗是微不足道的,除非某对象的生成对效率要求特别
高。(3)缺少 IDE 重构操作的支持,如果在 Eclipse 要对类改名,那么你还需
要去 XML 文件里手工去改了,这似乎是所有 XML 方式的缺憾所在。
IOC 实现初探
IOC 关注服务(或应用程序部件)是如何定义的以及他们应该如何定位他们依
赖的其它服务。通常,通过一个容器或定位框架来获得定义和定位的分离,容
器或定位框架负责:
保存可用服务的集合
提供一种方式将各种部件与它们依赖的服务绑定在一起
为应用程序代码提供一种方式来请求已配置的对象(例如,一个所有依赖都满足
的对象), 这种方式可以确保该对象需要的所有相关的服务都可用。
现有的框架实际上使用以下三种基本技术的框架执行服务和部件间的绑定: 
类型 1 (基于接口): 可服务的对象需要实现一个专门的接口,该接口提供了一
个对象,可以从用这个对象查找依赖(其它服务)。早期的容器 Excalibur 使用
这种模式。
类型 2 (基于 setter): 通过 JavaBean 的属性(setter 方法)为可服务对象指定
服务。HiveMind 和 Spring 采用这种方式。
类型 3 (基于构造函数): 通过构造函数的参数为可服务对象指定服务。
PicoContainer 只使用这种方式。HiveMind 和 Spring 也使用这种方式。
-----------------华丽丽的分割线,引用结束-------------------------Interface Driven Design 接口驱动
接口驱动有很多好处,可以提供不同灵活的子类实现,增加代码稳定和健壮性
等等,但是接口一定是需要实现的,也就是如下语句迟早要执行:AInterface a 
= new AInterfaceImp(); 这样一来,耦合关系就产生了。
如:
Class A
{
AInterface a;
A(){}
aMethod()
{
a = new AInterfaceImp();
}
}
ClassA 与 AInterfaceImp 就是依赖关系,如果想使用 AInterface 的另外一个实
现就需要更改代码了。
当然我们可以建立一个 Factory 来根据条件生成想要的 AInterface 的具体实现,
即:
InterfaceImplFactory
{
AInterface create(Object condition)
{
if(condition = condA)
{
return new AInterfaceImpA();
}
elseif(condition = condB)
{
return new AInterfaceImpB();
}
else
{
return new AInterfaceImp();
}
}
}
表面上是在一定程度上缓解了以上问题,但实质上这种代码耦合并没有改变。
通过 IoC 模式可以彻底解决这种耦合,它把耦合从代码中移出去,放到统一的
XML 文件中,通过一个容器在需要的时候把这个依赖关系形成,即把需要的接口
实现注入到需要它的类中,这可能就是“依赖注入”说法的来源了。
IOC 模式系统中,通过引入实现 IOC 模式的 IOC 容器,即可由 IOC 容器来管理对
象的生命周期、依赖关系等,从而使得应用程序的配置和依赖性规范与实际的
应用程序代码分开。其中一个特点就是通过文本的配置文件进行应用程序组件
间相互关系的配置,而不用重新修改并编译具体的代码。
当前比较知名的 IOC 容器有: Pico Container、 Avalon 、 Spring、 JBoss、 HiveMind、
EJB 等。其中,轻量级的有 Pico Container、Avalon、Spring、HiveMind 等,
超重量级的有 EJB,而半轻半重的有容器有 JBoss,Jdon 等。
可以把 IoC 模式看做是工厂模式的升华,可以把 IoC 看作是一个大工厂,只不
过这个大工厂里要生成的对象都是在 XML 文件中给出定义的,然后利用 Java 的
“反射”编程,根据 XML 中给出的类名生成相应的对象。从实现来看,IoC 是把
以前在工厂方法里写死的对象生成代码,改变为由 XML 文件来定义,也就是把
工厂和对象生成这两者独立分隔开来,目的就是提高灵活性和可维护性。
IoC 中最基本的 Java 技术就是“反射”编程。反射又是一个生涩的名词,通俗
的说反射就是根据给出的类名(字符串)来生成对象。这种编程方式可以让对
象在生成时才决定要生成哪一种对象。反射的应用是很广泛的,象 Hibernate、
String 中都是用“反射”做为最基本的技术手段。
IoC 最大的好处是什么?因为把对象生成放在了 XML 里定义,所以当我们需要换
一个实现子类将会变成很简单(一般这样的对象都是现实于某种接口的),只
要修改 XML 就可以了。 

Ioc与DI