转:什么是DIP、IoC、DI


DIP
依赖倒置原则DIP(Dependency-Inversion Principles)html

 

IoC
控制反转(Inversion of Control,IoC),简言之就是代码的控制器交由系统控制,而不是在代码内部,经过IoC,消除组件或者模块间的直接依赖,使得软件系统的开发更具柔性和扩展性。控制反转的典型应用体如今框架系统的设计上,是框架系统的基本特征,不论是.NET Framework抑或是Java Framework都是创建在控制反转的思想基础之上。服务器

控制反转不少时候被看作是依赖倒置原则的一个同义词,其概念产生的背景大概来源于框架系统的设计,例如.NET Framework就是一个庞大的框架(Framework)系统。在.NET Framework大平台上能够很容易地构建ASP.NET Web应用、Silverlight应用、Windows Phone应用或者Window Azure Cloud应用。不少时候,基于.NET Framework构建自定义系统的方式就是对.NET Framework自己的扩展,调用框架提供的基础API,扩展自定义的系统功能和行为。然而,无论如何新建或者扩展自定义功能,代码执行的最终控制权仍是回到框架中执行,再交回应用程序。黄忠诚先生曾经在Object Builder Application Block一文中给出一个较为贴切的举例,就是在Window From应用程序中,当Application.Run调用以后,程序的控制权交由Windows Froms Framework上。因此,控制反转更强调控制权的反转,体现了控制流程的依赖倒置,因此从这个意义上来讲,控制反转是依赖倒置的特例。框架

 

DI
依赖注入(Dependency Injection,DI),早见于Martin Flower的Inversion of Control Containers and the Dependency Injection pattern一文,其定义可归纳为:ide

客户类依赖于服务类的抽象接口,并在运行时根据上下文环境,由其余组件(例如DI容器)实例化具体的服务类实例,将其注入到客户类的运行时环境,实现客户类与服务类实例之间松散 的耦合关系。函数

常见的三种注入方式
简单而言,依赖注入的方式被总结为如下三种。ui

接口注入(Interface Injection),将对象间的关系转移到一个接口,以接口注入控制。this

首先定义注入的接口:线程

public interface IRunnerProvider
{
void Run(Action action);
}
为注入的接口实现不一样环境下的注入提供器,本例的系统是一个后台处理程序提供了运行环境的多种可能,默认状况下将运行于单独的线程,或者经过独立的Windows Service进程运行,那么须要为不一样的状况实现不一样的提供器,例如: 设计

 

public class DefaultRunnerProvider : IRunnerProvider
{
public void Run(Action action)
{
var thread = new Thread(() => action());
thread.Start();
}
}htm


对于后台服务的Host类,经过配置获取注入的接口实例,而Run方法的执行过程则被注入了接口所定义的逻辑,该逻辑由上下文配置所定义:

 

public class RunnerHost : IDisposable
{
IRunnerProvider provider = null;

public RunnerHost()
{
// Get Provider by configuration
provider = GetProvider(config.Host.Provider.Name);
}

public void Run()
{
if (provider != null)
{
provider.Run(() =>
{
// exceute logic in this provider,
if provider is DefualtRunnerProvider,
// then this logic will run in a new thread context.
});
}
}
}


接口注入,为无须从新编译便可修改注入逻辑提供了可能,GetProvider方法彻底能够经过读取配置文件的config.Host.Provider.Name内容,来动态地建立对应的Provider,从而动态地改变BackgroundHost的Run()行为。

构造器注入(Constructor Injection),客户类在类型构造时,将服务类实例以构造函数参数的形式传递给客户端,所以服务类实例一旦注入将不可修改。

 

public class PicWorker
{
}

public class PicClient
{
private PicWorker worker;

public PicClient(PicWorker worker)
{
// 经过构造器注入
this.worker = worker;
}
}


属性注入(Setter Injection),经过客户类属性设置的方式,将服务器类实例在运行时设定为客户类属性,相较构造器注入方式,属性注入提供了改写服务器类实例的可能。

 

public class PicClient
{
private PicWorker worker;

// 经过属性注入
public PicWorker Woker
{
get { return this.worker; }
set { this.worker = value; }
}
}


关系
整体而言,DIP、IoC还有DI之间有着剪不断理还乱的关系,其中DIP是对于依赖关系的理论总结,而IoC和DI则体现为具体的实践模式。IoC和DI为消除模块或者类之间的耦合关系提供了有效的解决方案,从而保证了依赖于抽象和稳定模块或者类型,也就意味着坚持了DIP原则的大方向。


而IoC和DI之间的区别主要体如今关注场合的不一样:IoC强调控制权的反转做用,着眼于流程控制的场合;而DI则关注层次与层次、组件与组件、模块与模块或者类型与类型之间的"倒置",体现为设计模型上的依赖模式解构。

这篇短文基本上是改编自Martin Fowler的Inversion of Control Containers and the Dependency Injection pattern,目的呢,是让读者可以在最短期内了解IoC的概念。这也是我一向的“风格”:最短的文字、最精要的内容、最清晰的说明。但愿我能作到,自勉^_^

 

在J2EE应用开发中,常常遇到的问题就是:如何将不一样的组件组装成为一个内聚的应用程序?IoC模式能够解决这个问题,其目标是将组件的配置与使用分离开。

IoC,Inversion of Control,控制反转[1],其原理是基于OO设计原则的The Hollywood Principle:Don't call us, we'll call you。也就是说,全部的组件[2]都是被动的(Passive),全部的组件初始化和调用都由容器负责。组件处在一个容器当中,由容器负责管理。

要说明IoC模式最好的方法是使用代码。下边是一段正常的代码。

class ClassA...

public String aMethod(String arg){

String result = instanceOfClassB.bMethod();

do something;

return result;

}

在上边的代码里,咱们要解决的问题是:ClassA如何得到ClassB的实例?一个最直接的方法是在aMethod里声明:

IClassB instanceOfClassB = new ClassB();

这里使用了一个接口IClassB。

问题是,若是出现这样的状况:继续使用ClassA,但要求用IClassB的另外一个实现ClassB2代替ClassB呢?更归纳一点说:ClassA怎样才能找到IClassB的具体实现?很明显,上述代码增长ClassA和ClassB的耦合度,以至于没法在不修改ClassA的状况下变动IClassB的具体实现。

IoC模式就是用于解决这样的问题。固然,还有其余的方法,好比Service Locator模式,但如今咱们只关注IoC。如前所述,IoC容器负责初始化组件(如IClassB),并将实例交给使用者。使用代码或配置文件以声明的方式将接口与实例关联起来,IoC容器负责进行实际的调用处理。对于调用者,只须要关注接口就好了。

根据实例传入方式的不一样,IoC分为type 1 IoC(接口注入[3])、type 2 IoC(设值方法注入)和type 3 IoC(构造子注入)。分别用代码说明以下:

type 1 IoC(接口注入)

public interface GetClassB {

void getClassB(IClassB instanceOfClassB);

}

 

class ClassA implements GetClassB…

IClassB instanceOfClassB;

void getClassB(IClassB instanceOfClassB) {

this.instanceOfClassB = instanceOfClassB;

}

type 2 IoC(设值方法注入)

class ClassA...

IClassB instanceOfClassB;

public void setFinder(IClassB instanceOfClassB) {

this.instanceOfClassB = instanceOfClassB;

}

type 3 IoC(构造子注入)

class ClassA…

ClassB instanceOfClassB;

public classA(IClassB instanceOfClassB) {

this. instanceOfClassB = instanceOfClassB;

}

Spring使用的是type 2 IoC。

 

参考:http://leshy.iteye.com/blog/69034http://book.51cto.com/art/201108/284974.htmhttp://baike.baidu.com/view/1486379.htmhttp://www.cnblogs.com/xugang2008/archive/2011/07/06/2098889.htmlhttp://www.cnblogs.com/winsonet/archive/2010/02/09/1666204.htmlhttp://www.cnblogs.com/n-pei/archive/2011/02/15/1955460.html

相关文章
相关标签/搜索