0X1 什么是依賴注入
依賴注入(Dependency Injection),是這樣一個過程:某客戶類只依賴於服務類的一個接口,而不依賴於具體服務類,所以客戶類只定義一個注入點。在程序運行過程中,客戶類不直接實例化具體服務類實例,而是客戶類的運行上下文環境或專門組件負責實例化服務類,然后將其注入到客戶類中,保證客戶類的正常運行。
圖1
如圖1所示,數據庫操作類DataManager中依賴的IDataBase的接口,而不是以來IDataBase的具體實現類,這樣的好處是可以讓我們的程序具有擴展性:無論我們要使用SqlServer當我們的數據庫操作類還是用Mysql,我們需要改動的地方都很少。
0X2 一個Demo理解Di
我們創建一個控制台程序,並按照圖1中所標識的關系創建四個類。
public class DataManager { private IDataBase _database; public DataManager(IDataBase database) { this._database = database; } public void Add() { _database.Add(); } public void Delete() { _database.Delete(); } public void Update() { _database.Update(); } public void Select() { _database.Select(); } }
IDataBase接口
public interface IDataBase { string DbName { get; } void Select(); void Update(); void Delete(); void Add(); }
public class SqlServer : IDataBase { public string DbName { get { return "SqlServer"; } } public void Add() { Console.WriteLine("Add in " + DbName); } public void Delete() { Console.WriteLine("Delete in " + DbName); } public void Select() { Console.WriteLine("Select in " + DbName); } public void Update() { Console.WriteLine("Update in " + DbName); } }
public string DbName { get { return "Mysql"; } } public void Add() { Console.WriteLine("Add in " + DbName); } public void Delete() { Console.WriteLine("Delete in " + DbName); } public void Select() { Console.WriteLine("Select in " + DbName); } public void Update() { Console.WriteLine("Update in " + DbName); }
如果我們要用Sqlserver作為數據庫實現類的話,傳統寫法我們要New Sqlserver,如下圖:
項目早期使用的是Sqlserver數據庫沒問題,后來BOSS忽然要改成Mysql數據庫,你心里面一想,沒問題啊,無非就是把New后面的Sqlserver換成Mysql嘛,簡單。於是你就開始改,越改越不對勁,已經你已經發現當前項目已經有好幾十個地方用到New Sqlserver(),而剩余的數量往往還是未知的。這個時候你就在想,有沒有方法可以讓我只需要改一個地方其他地方不用動就可以呢?答案是肯定的,目前這種方法實現有很多種,最簡單的無非就是工廠模式。但是,今天,我們不用工廠,我們將使用Ninject來實現這種功能。
0X3 Ninject的使用
Ninject是一個IOC容器,用來解決程序中組件的耦合問題,它的目的在於做到最少配置。其他的的IOC工具過於依賴配置文件,需要使用assembly-qualified名稱來進行定義,庸長且復雜常常因為打錯字而破壞程序。這些是他的優點,也是為什么要選擇它。
安裝Ninject
打開Nuget程序包管理控制台輸入“Install-Package Ninject”即可安裝Ninject。
Ninject使用步驟
我們一般會在程序啟動的入口來創建Ninject的對象負責類型的注冊。
1 static void Main(string[] args) 2 { 3 //實例化Ninject對象 4 IKernel Kerner = new StandardKernel(); 5 }
使用Ninject對象分兩個步驟,第一步是把接口對象或者說被依賴的對象(IDataBase)綁定到Ninject中,然后在為其綁定對應的實例類型(如果要使用SqlServer則就綁定SqlServer)。
//實例化Ninject對象 IKernel Kerner = new StandardKernel(); //綁定對象 Kerner.Bind<IDataBase>().To<SqlServer>();
第二步則是通過Ninject的Get方法獲取IDataBase的實現類
var Db = Kerner.Get<IDataBase>(); //由於上面IDataBase綁定的是SqlServer類型,所以這里獲取的類型是SqlServer
上面的代碼大家可能體會不到使用Ninject的好處,也沒有體會到依賴注入的奧妙所在。依賴注入大致分為三類:接口注入,函數注入,屬性注入。我們來通過一個例子來演示屬性注入。
我們增加一個IShowDBInfo的接口類,其有一個Show方法。然后添加一個Show類實現IShowDBInfo接口:
public class Show1 : IShowDBInfo { public void Show() { Console.WriteLine(this.GetType().FullName); } }
我們給DataManager添加一個IShowDBInfo屬性並增加一個Show()方法:
public class DataManager { private IDataBase _database; private IShowDBInfo _showDbInfo; public DataManager(IDataBase database, IShowDBInfo ishowdbinfo) { this._database = database; _showDbInfo = ishowdbinfo; } //省略Add,Updata,Delete,Select方法 public void Show() { _showDbInfo.Show(); } }
在應用程序啟動的時候注冊IShow類和注冊DataManager類並啟動程序:
static void Main(string[] args) { //實例化Ninject對象 IKernel Kerner = new StandardKernel(); //綁定對象 Kerner.Bind<IDataBase>().To<SqlServer>(); Kerner.Bind<IShowDBInfo>().To<Show1>(); Kerner.Bind<DataManager>().ToSelf(); var dataManager=Kerner.Get<DataManager>(); dataManager.Show(); Console.Read(); }
從上代碼以及運行結果來看,我們只需要在向Ninject實例里面注冊對象,然后在其他類中使用的時候我們只需要定義接口就可以了,並不需要實例化對象。這樣做的話可以使我們和其他層進行松耦合。