依賴注入和控制反轉究竟是什麼意思?mysql
控制反轉(Ioc):調用者再也不建立被調用者的實例,由IOC容器框架建立(C#中經常使用的IOC框架有Autofac/Unity等等),這種方式稱爲控制反轉sql
依賴注入(DI):容器框架將建立好的實例注入到調用者稱爲依賴注入數據庫
依賴倒置原則(DIP)編程
高層模塊不該依賴於低層模塊,二者應該依賴於抽象。設計模式
抽象不不該該依賴於實現,實現應該依賴於抽象。框架
使用Ioc的好處是什麼?函數
控制反轉是面向對象編程中的一種設計原則,能夠用來下降代碼之間的耦合度,Ioc把建立和查找依賴對象的控制權交給容器,由容器進行注入,因此對象與對象之間是鬆散耦合,傳統的應用程序都是由咱們在類內部主動建立依賴對象,從而致使類與類之間是緊耦合spa
舉例設計
class SqlDal { public void Add() { Console.WriteLine("向SQLServer數據庫添加一條新訂單"); } } class Order { SqlDal sqlDal = new SqlDal(); public void Add() { sqlDal.Add(); } }
首先定義了SqlDal類用於SqlServer數據庫的讀寫操做,再定義Order類負責訂單的邏輯處理,由於訂單數據是要插入到數據庫的,因此在Order類中定了SqlDal類的變量並初始化.這裏Order是依賴於SqlDal類的code
控制檯調用
static void Main(string[] args) { Order order = new Order(); order.Add(); Console.ReadKey(); }
這是傳統開發中比較常見的方式,若是這時候數據庫改成了mysql,那麼SqlDal是沒法繼續使用了,須要從新定義mysqlDal,負責mysql數據庫的讀寫操做
class MySqlDal { public void Add() { Console.WriteLine("向MySql數據庫添加一條新訂單"); } }
因爲Order類中直接引用了SqlDal類的對象,因此也須要同步修改成MySqlDal
class Order { MySqlDal mySqlDal = new MySqlDal(); public void Add() { mySqlDal.Add(); } }
OK,能夠知足當前需求了,可是若是後期相似的狀況再次出現,就意味着須要將剛纔的操做從新作一次,顯然這不是一個良好的設計,類與類之間是高度耦合的,可擴展性較差,它違背了DIP原則,高層模塊Order不該依賴於底層模塊SqlDal、MySqlDal,二者應該依賴於抽象
改寫代碼
public interface IDal { void Add(); } class SqlDal : IDal { public void Add() { Console.WriteLine("向SQLServer數據庫添加一條新訂單"); } } class Order { private IDal _dal; /// <summary> /// 構造函數注入 /// </summary> /// <param name="dal"></param> public Order(IDal dal) { _dal = dal; } public void Add() { _dal.Add(); } }
第一步:定義接口IDal,添加方法Add()
第二步:定義SqlDal繼承IDal接口並實現接口中的Add()方法
第三步:在Order類中添加私有變量用於存儲抽象並在構造函數中傳遞具體依賴對象
控制檯調用
static void Main(string[] args) { Order order = new Order(new SqlDal()); order.Add(); Console.ReadKey(); }
class MySqlDal : IDal { public void Add() { Console.WriteLine("向MySql數據庫添加一條新訂單"); } }
Order order = new Order(new MySqlDal()); order.Add();
輸出結果是同樣的,可是這裏將依賴對象SqlDal對象的建立和綁定轉移到了Order外部來實現,這就解除了Order與SqlDal類的耦合關係,若是如今出現須要更改數據庫爲MySql的需求,只須要定義MySqlDal類繼承IDal並實現Add()方法,而後外部綁定依賴,不須要修改Order類內部的代碼便可實現替換,很明顯這種方式程序的可擴展性更高
屬性注入
上面所示的方式是在Order類的構造函數中注入依賴對象,還可使用屬性注入的方式,顧名思義,屬性注入是經過屬性來傳遞依賴,所以在Order類中定義一個屬性
class Order { private IDal _dal; /// <summary> /// 屬性注入 /// </summary> public IDal Dal { get { return _dal; } set { _dal = value; } }
public void Add() { _dal.Add(); } }
在控制檯調用時給屬性賦值從而傳遞依賴
static void Main(string[] args) { Order order = new Order(); order.Dal = new SqlDal(); order.Add(); Console.ReadKey(); }
接口注入
相比構造函數注入和屬性注入,接口注入顯得有些複雜,使用也不常見。具體思路是先定義一個接口,包含一個設置依賴的方法。而後依賴類,繼承並實現這個接口
public interface IDependent { void SetDepend(IDal idal); }
class Order: IDependent { private IDal _dal; public void Add() { _dal.Add(); } public void SetDepend(IDal idal) { _dal = idal; } }
經過SetDepend方法傳遞依賴
static void Main(string[] args) { Order order = new Order(); order.SetDepend(new SqlDal()); order.Add(); Console.ReadKey(); }
Ioc容器
前面全部的例子中,咱們都是經過手動的方式來建立依賴對象,並將引用傳遞給被依賴模塊,對於大型項目來講,相互依賴的組件比較多。若是還用手動的方式本身來建立和注入依賴的話,顯然效率很低,並且每每還會出現不可控的場面。正因如此,Ioc容器誕生了。Ioc容器其實是一個DI框架,它能簡化咱們的工做量。它包含如下幾個功能
總結:DIP是軟件設計的一種思想,Ioc則是基於DIP衍生出的一種軟件設計模式。DI是Ioc的具體實現方式之一,使用最爲普遍。Ioc容器是DI構造函注入的框架,它管理着依賴項的生命週期以及映射關係