关于 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 就能够了。 编程