一、為什么要使用依賴注入框架
依賴注入框架也叫IoC容器。它的作用使類與類之間解耦
我們看看為什么要用依賴注入框架,舉個幾個梨子:
1,高度耦合的類
有一個Order類,Order類是用於訂單操作的,DataAccess使用的sqlserver的方式查詢訂單。看看代碼:
public class Order { private DataAccess dataAccess = new DataAccess(); public string QueryOrder() { return dataAccess.QueryOrder(); } } public class DataAccess { public string QueryOrder() { return "sqlserver查詢Order"; } }
看到這兩個類(Order,DataAccess),它們出現了高度耦合。如果產品汪突然狂犬病大發讓我們換成MySql方式查詢,我們不得不修改Order類的private DataAccess data = new DataAccess() 和DataAccess的QueryOrder方法。這里違反了開放封閉原則(對擴展開放,對修改關閉),當然一個項目不只只有訂單(Order)操作,還有購物車、產品等等操作,那改動起來將會是一場噩夢。
2,使用依賴倒轉原則來改進
依賴倒轉原則口訣:高層次模塊不應該依賴於低層次模塊,要依賴抽象,不要依賴具體。
口訣聽着很繞口,其實理解起來並不難,看下面的類圖,Order相當於是高層模塊,SqlServerData和MySqlData相當於底層模塊,高層模塊依賴於接口,所以可以隨時更換底層模塊
我們現在把DataAccess抽象為接口,使SqlServerData和MySqlData實現IDataAccess
public class Order { private IDataAccess dataAccess = new MySqlData(); public string QueryOrder() { return dataAccess.QueryOrder(); } } public interface IDataAccess { string QueryOrder(); } public class SqlServerData : IDataAccess { public string QueryOrder() { return "sqlserver查詢Order"; } } public class MySqlData : IDataAccess { public string QueryOrder() { return "MySql查詢Order"; } }
現在我們高層模塊依賴於接口,如果產品汪再叫我們換Oracle數據庫,我們就可以再添加一個OracleData類,然后實現IDataAccess接口,然后在Order類中的private IDataAccess dataAccess = new MySqlData()改為private IDataAccess dataAccess = new OracleData()。雖然改動的地方減少了,但是我們還是修改了類。可是我們並不希望修改類,就可以更換數據訪問,這就需要解耦,需要用到Ioc容器,我們的Ninject終於該出場了,出場費還不低哦!
二、實戰Ninject
1,使用注冊機制
首先安裝一個Ninject的Dll,我們用NuGet安裝。
①反鍵項目引用,選中管理NuGet程序包
②搜索Ninject,點擊安裝
③代碼實現(只實現Order類操作,Product類操作與Order類一致)
IDataAccess:
using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace RegisterNinject { public interface IDataAccess { string QueryOrder(); } }
MySqlDataOrder:
using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace RegisterNinject { public class MySqlDataOrder : IDataAccess { public string QueryOrder() { return "MySql查詢Order"; } } }
SqlServerDataOrder:
using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace RegisterNinject { public class SqlServerDataOrder : IDataAccess { public string QueryOrder() { return "sqlserver查詢Order"; } } }
Register:
using System; using System.Collections.Generic; using System.Linq; using System.Text; using Ninject; //引入命名空間 namespace RegisterNinject { public class Register { private StandardKernel _kernel = new StandardKernel(); // 在這里注冊 public Register() { _kernel.Bind<IDataAccess>().To<MySqlDataOrder>(); //_kernel.Bind<IDataAccess>().To<SqlServerDataOrder>(); //_kernel.Bind<IDataProduct>().To<SqlServerDataProduct>(); } //獲取 public TInterface Get<TInterface>() { return _kernel.Get<TInterface>(); } public void Dispose() { _kernel.Dispose(); } } }
Order:
using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace RegisterNinject { public class Order { private Register reg = new Register(); public string QueryOrder() { return reg.Get<IDataAccess>().QueryOrder(); } } }
這樣,媽媽再也不用擔心我換數據庫了。如果產品汪再讓我們換回sqlserver數據庫[神經病](小插曲:換數據庫是舉的例子,Ioc容器的意義是讓類與類之間解耦的,不是換數據庫用的!),我們只需要在Register類中的構造函數中修改注冊即可。
有人說,"你還是修改了類呀!"。Register類的定位不一樣,他是一個公共類,專門提供注冊機制的。如果不去要修改類,就能完成換數據庫,那就要引入新的概念———熱插拔技術。
2,使用Xml文件(熱插拔)
現在我們用xml文件的方式,動態的更換接口。我們需要建一個xml文件。把他放在項目中。
Register.xml
<?xml version="1.0" encoding="utf-8" ?> <module name="register"> <bind service="XmlNinject.IDataAccess,XmlNinject" to="XmlNinject.SqlServerDataOrder,XmlNinject"/> </module>
注意:module元素,name屬性,bind元素,service屬性,to屬性為規定的元素屬性,不能寫成別的。格式也要正確。
然后更改下Register:
using System; using System.Collections.Generic; using System.Linq; using System.Text; using Ninject; //引入命名空間 using Ninject.Extensions.Xml;//引入命名空間 namespace XmlNinject { public class Register { private StandardKernel _kernel = new StandardKernel(); // 以后這里就不用更改這里了,只需要該xml文件就可以了 public Register() { var settings = new NinjectSettings() { LoadExtensions = false }; _kernel = new StandardKernel(settings, new XmlExtensionModule()); _kernel.Load("Xml/Register.xml"); } //獲取 public TInterface Get<TInterface>() { return _kernel.Get<TInterface>(); } public void Dispose() { _kernel.Dispose(); } } }
以后要更換接口,直接更改xml文件就可以了。
源碼下載http://pan.baidu.com/s/1sjJXVrv