什么是IoC
IoC是Inversion of Control的縮寫,翻譯過來為“控制反轉”。簡單來說,就是將對象的依賴關系交由第三方來控制。在理解這句話之前,我們先來回顧一下IoC的演化。
Ioc前世今生
傳統的new class的方式
我們寫了一個ChineseSpeaker的類,他有一個SayHello的方法並調用輸出控制台:
class Program
{
static void Main(string[] args)
{
ChineseSpeaker chineseSpeaker= new ChineseSpeaker();
chineseSpeaker.SayHello();
}
}
public class ChineseSpeaker
{
public void SayHello()
{
Console.WriteLine("你好!!!");
}
}
上面看起來沒有任何問題,一切都很好,但是有一天英國演講者打招呼的話,我們就需要新建了一個BritishSpeaker類:
class Program
{
static void Main(string[] args)
{
//ChineseSpeaker chineseSpeaker = new ChineseSpeaker();
//chineseSpeaker.SayHello();
BritishSpeaker britishSpeaker = new BritishSpeaker();
britishSpeaker.SayHello();
}
}
public class BritishSpeaker
{
public void SayHello()
{
Console.WriteLine("Hello!!!");
}
}
//ChineseSpeaker 同上面的代碼一樣
當出現“日本人”、“印度人”時,我們不得不修改和重新編譯代碼。當程序代碼和邏輯不復雜的時候問題不大,但當程序變大的時候程序猿就苦逼了。
Interface方式
因此,我們把代碼改成:
public interface ISpeak
{
void SayHello();
}
public class BritishSpeaker : ISpeak
{
public void SayHello()
{
Console.WriteLine("Hello!!!");
}
}
public class ChineseSpeaker : ISpeak
{
public void SayHello()
{
Console.WriteLine("你好!!!");
}
}
class Program
{
static void Main(string[] args)
{
//ChineseSpeaker chineseSpeaker = new ChineseSpeaker();
//chineseSpeaker.SayHello();
//BritishSpeaker britishSpeaker = new BritishSpeaker();
//britishSpeaker.SayHello();
ISpeak speak;
if (args.Length > 0 && args[0] == "Chinese")
{
speak = new ChineseSpeaker();
}
else
{
speak = new BritishSpeaker();
}
speak.SayHello();
}
}
這時候我們不知不覺的用到了面向對象六大原則中的依賴倒轉原則(DIP),高層模塊不依賴於低層模塊的實現,而低層模塊依賴於高層模塊定義的接口。 好,讓我們回到IoC,比較上面的兩種寫法:
- 傳統的寫法類在定義的瞬間就已經決定具體的類型,他的流程是從上到下的
- 使用interface的寫法是在實例化時才決定類的具體類型,也就是用到的時候才會new(),他的流程是new后面來控制的
這時候我們再來看IoC的意思是控制反轉,就能大概理解了。傳統的寫法流程屬於從上到下,而interface寫法則是由new()其他的類來決定類的實現,因此控制的流程反轉了。
DI是什么
利用interface的方式,可以讓類在使用的時候再決定由哪個具體類來實現。那該如何實現這種方式呢?這時就有一個新的名稱出現了,就是Dependency Injection(依賴注入),簡稱DI。DI有三種方式,分別是構造函數注入、屬性注入、接口注入
構造函數注入
public class Printer
{
private ISpeak _speak;
public Printer(ISpeak speak)//構造函數注入
{
_speak = speak;
}
}
class Program
{
static void Main(string[] args)
{
//ChineseSpeaker chineseSpeaker = new ChineseSpeaker();
//chineseSpeaker.SayHello();
//BritishSpeaker britishSpeaker = new BritishSpeaker();
//britishSpeaker.SayHello();
//ISpeak speak;
//if (args.Length > 0 && args[0] == "Chinese")
//{
// speak = new ChineseSpeaker();
//}
//else
//{
// speak = new BritishSpeaker();
//}
//speak.SayHello();
Printer print;
if (args.Length > 0 && args[0] == "Chinese")
{
print = new Printer(new ChineseSpeaker());
}
else
{
print = new Printer(new BritishSpeaker());
}
}
}
屬性注入
public class Printer
{
public ISpeak Speaker { get; set; }
}
class Program
{
static void Main(string[] args)
{
//ChineseSpeaker chineseSpeaker = new ChineseSpeaker();
//chineseSpeaker.SayHello();
//BritishSpeaker britishSpeaker = new BritishSpeaker();
//britishSpeaker.SayHello();
//ISpeak speak;
//if (args.Length > 0 && args[0] == "Chinese")
//{
// speak = new ChineseSpeaker();
//}
//else
//{
// speak = new BritishSpeaker();
//}
//speak.SayHello();
Printer print = new Printer();
if (args.Length > 0 && args[0] == "Chinese")
{
print.Speaker = new ChineseSpeaker();
}
else
{
print.Speaker = new BritishSpeaker();
}
}
}
接口注入
//接口注入
public interface IPrint
{
void SetSpeaker(ISpeak speak);
}
public class Printer : IPrint
{
private ISpeak _speak;
public void SetSpeaker(ISpeak speak)
{
_speak = speak;
}
}
class Program
{
static void Main(string[] args)
{
//ChineseSpeaker chineseSpeaker = new ChineseSpeaker();
//chineseSpeaker.SayHello();
//BritishSpeaker britishSpeaker = new BritishSpeaker();
//britishSpeaker.SayHello();
ISpeak speak;
if (args.Length > 0 && args[0] == "Chinese")
{
speak = new ChineseSpeaker();
}
else
{
speak = new BritishSpeaker();
}
Printer printer = new Printer();
printer.SetSpeaker(speak);
}
}
IoC與DI的關系
我的理解是IoC是一種理念,DI則是它的具體實現方式
IoC Container
IoC Container幫我們在項目運行時動態的創建實例,它主要功能如下:
- 動態創建、注入依賴對象
- 管理對象生命周期
- 映射依賴關系
IoC Container技術實現的原理就是“反射(Reflection)”。利用反射動態的創建對象,把依賴關系注入到指定對象中。一般常用的注入方式是構造函數注入和屬性注入
Service Locator模式
服務定位模式也是IoC理念的一種實現。實現原理:通過ServiceLocator類提供實現IServiceLocator接口的單例,並負責管理已注冊實例的創建和訪問。通常結合工廠模式來結合使用。
Service Locator與IoC Container都是IoC的具體實現方式。不同的是Service Locator沒有提供管理對象生命周期的功能
.NET 平台下的IoC Container框架
Ninject: http://www.ninject.org/
Castle Windsor: http://www.castleproject.org/container/index.html
Autofac: http://code.google.com/p/autofac/
StructureMap: http://docs.structuremap.net/
Unity: http://unity.codeplex.com/
Spring.NET: http://www.springframework.net/
結束語
我在學習IoC過程中,學以致用,自己模仿Nject實現了一個IoC Container框架,可以用FluentAPI和xml配置依賴關系,希望對大家有幫助。項目地址:https://github.com/Khadron/Peace
