控制反轉(Inversion of Control,IoC),簡言之就是代碼的控制器交由系統控制,而不是在代碼內部,經過IoC,消除組件或者模塊間的直接依賴,使得軟件系統的開發更具柔性和擴展性。控制反轉的典型應用體如今框架系統的設計上,是框架系統的基本特徵,無論是.NET Framework抑或是Java Framework都是創建在控制反轉的思想基礎之上。html
控制反轉不少時候被看作是依賴倒置原則的一個同義詞,其概念產生的背景大概來源於框架系統的設計,例如.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上。因此,控制反轉更強調控制權的反轉,體現了控制流程的依賴倒置,因此從這個意義上來講,控制反轉是依賴倒置的特例。服務器
依賴注入(Dependency Injection,DI),早見於Martin Flower的Inversion of Control Containers and the Dependency Injection pattern一文,其定義可歸納爲:框架
客戶類依賴於服務類的抽象接口,並在運行時根據上下文環境,由其餘組件(例如DI容器)實例化具體的服務類實例,將其注入到客戶類的運行時環境,實現客戶類與服務類實例之間鬆散的耦合關係。ide
(1)常見的三種注入方式函數
簡單而言,依賴注入的方式被總結爲如下三種。ui
首先定義注入的接口:this
public interface IRunnerProviderspa
{.net
void Run(Action action);線程
}
爲注入的接口實現不一樣環境下的注入提供器,本例的系統是一個後臺處理程序提供了運行環境的多種可能,默認狀況下將運行於單獨的線程,或者經過獨立的Windows Service進程運行,那麼須要爲不一樣的狀況實現不一樣的提供器,例如:
public class DefaultRunnerProvider : IRunnerProvider
{
#region IRunnerProvider Members
public void Run(Action action)
{
var thread = new Thread(() => action());
thread.Start();
}
#endregion
}
對於後臺服務的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()行爲。
public class PicWorker
{
}
public class PicClient
{
private PicWorker worker;
public PicClient(PicWorker worker)
{
// 經過構造器注入
this.worker = worker;
}
}
public class PicClient
{
private PicWorker worker;
// 經過屬性注入
public PicWorker Woker
{
get { return this.worker; }
set { this.worker = value; }
}
}
另外,在.NET平臺下,除了Martin Flower大師提出的三種注入方式以外,還有一種更優雅的選擇,那就是依靠.NET特有的Attribute實現,以ASP .NET MVC中的Action Filter爲例:
[HttpPost]
public ActionResult Register(RegisterModel model)
{
// 省略註冊過程
return View(model);
}
其中,HttpPostAttribute就是經過Attribute方式爲Register Action注入了自動檢查Post請求的邏輯,一樣的注入方式普遍存在於ASP .NET MVC的不少Filter邏輯中。
[AttributeUsage(AttributeTargets.Method, AllowMultiple = false, Inherited = true)]
public sealed class HttpPostAttribute : ActionMethodSelectorAttribute
{
// Fields
private static readonly AcceptVerbsAttribute _innerAttribute = new AcceptVerbsAttribute(HttpVerbs.Post);
// Methods
public override bool IsValidForRequest(ControllerContext controllerContext, MethodInfo methodInfo)
{
return _innerAttribute.IsValidForRequest(controllerContext, methodInfo);
}
}
關於Attribute的詳細內容,請參考8.3節「歷史糾葛:特性和屬性」,其中的TrimAttribute特性正是應用Attribute注入進行屬性Trim過濾處理的典型應用。
轉自:http://www.cnblogs.com/jyshis/archive/2011/09/15/2177279.html