轉:什麼是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

相關文章
相關標籤/搜索