依賴倒置(Dependency Inversion Principle,縮寫DIP)是面向對象六大基本原則之一。他是指一種特定的的解耦形式,使得高層次的模塊不依賴低層次的模塊的實現細節,依賴關係被顛倒(反轉),從而使得低層次模塊依賴於高層次模塊的需求抽象.ide
該原則規定:函數
經過以下一個簡單的示例,咱們來看一下,咱們經過一個簡單地下單流程向咱們的用戶發送相關的短信或者郵件.設計
public SendingEmail { public void Send(string message){ //do something } } public Ordering { SendingEmail _sendingEmail=null; public void Order(string message){ //Order business operation if(_sendingEmail == null) { _sendingEmail=new SendingEmail(); } _sendingEmail.Send(message); } }
這樣看咱們的代碼沒問題,目前只要咱們完成了訂單操做那麼,那麼則會觸發發送功能,可是他卻違反了DIP,由於Ordering類依賴於SendingEmail類,而SendingEmail類不是抽象類,而是一個具體的類.那咱們再來想一個若是這時候業務口的人過來向咱們提出了一個新的需求,要求咱們改成短信而不是Email,那麼咱們須要怎麼改?對象
public class SendingSMS { public void Send(string message){ //do something } } public Ordering { SendingEmail _sendingEmail=null; SendingSMS _sendingSMS=null; bool isSendingSMS=true; public void Order(string message){ //Order business operation if(isSendingSMS){ if(_sendingSMS == null) { _sendingSMS=new SendingSMS(); } _sendingSMS.Send(message); }else{ if(_sendingEmail == null) { _sendingEmail=new SendingEmail(); } _sendingEmail.Send(message); } } }
根據上述需求咱們不得不建立更多的類,而且在Ordering類中聲明他,最後咱們還須要使用IF ELSE語句來決定使用SMS仍是使用電子郵件.可是當咱們有更多這種處理操做後,那麼可能比如今還混亂,這就意味着咱們必須在Ordering類中聲明更多新的具體類的實例.繼承
咱們須要抽離出來一種方式,讓高級模塊去依賴於抽象,用它來代替咱們實現類,該抽象將映射到實現類.接口
控制反轉(IoC)控制反轉(Inversion of Control,縮寫爲IOC)是面向對象中的設計原則,他能夠幫助咱們使高層模塊依賴於抽象,而不是底層模塊的具體實現.換句話說,他有助於實現(依賴倒置原則——DIP).生命週期
public interface ICustomerCommunication { void Send(string message); }
而後咱們修改SendingEmail和SendingSMS類以從ICustomerCommunication接口繼承.ip
public class SendingEmail:ICustomerCommunication { public void Send(string message){ //do something } } public class SendingSMS:ICustomerCommunication { public void Send(string message){ //do something } }
咱們再來修改一下Ordering類以使用該抽象接口ci
public Ordering { ICustomerCommunication _customerComm=null; bool isSendingSMS=true; public void Order(string message){ //Order business operation if(isSendingSMS){ if(_customerComm == null) { _customerComm=new SendingSMS(); } _customerComm.Send(message); }else{ if(_customerComm == null) { _customerComm=new SendingEmail(); } _customerComm.Send(message); } } }
經過如上修改咱們作的控制反轉更符合DIP.如今咱們的高級模塊只須要依賴於抽象,而不用去依賴實現.get
依賴注入(DI)依賴注入(Depeondency Injection,縮寫爲DI)是實現控制反轉的一種方式.經常使用的依賴注入方法有3種:
雖說經過上面代碼咱們實現了IoC,而且Ordering類依賴於ICustomerCommunication抽象,但咱們仍然在Ordering類中使用了實現類,這使用咱們沒法在類於類之間徹底解耦.
if(isSendingSMS){ if(_customerComm == null) { _customerComm=new SendingSMS(); } _customerComm.Send(message); }else{ if(_customerComm == null) { _customerComm=new SendingEmail(); } _customerComm.Send(message); }
那咱們再來講說DI,DI主要幫助咱們將實現注入到抽象的類(ICustomerCommunication接口)中.DI的主要減小類之間的耦合,而且將抽象和具體實現的綁定移除依賴類.
public class Ordering { ICustomerCommunication _customerComm=null; public Ordering(ICustomerCommunication customerComm){ _customerComm=customerComm; } public void Order(string message){ _customerComm.Send(message); } }
在上面的代碼中,構造函數將採用實現類對象綁定到接口中.若是咱們將SendingSMS的實現傳遞給這個類,咱們要作的就是聲明一個SendingSMS類的實例,而後將其傳遞給Ordering的構造函數,以下所示:
SendingSMS sendingSMS=new SendingSMS(); Ordering ordering=new Ordering(sendingSMS); ordering.Order("msg");
public class Ordering { public void Order(ICustomerCommunication customerComm,string message){ _customerComm=customerComm; _customerComm.Send(message); } }
調用方式以下所示
SendingSMS sendingSMS=new SendingSMS(); Ordering ordering=new Ordering(sendingSMS); ordering.Order(sendingSMS,"msg");
經過如上描述咱們知道了構造函數注入方法在整個生命週期中使用依賴類,而方法注入是將咱們的注入直接去限於該方法中,而後咱們再去了解一下屬性注入
public class Ordering { public ICustomerCommunication customerComm {get;set;} public void Order(string message){ _customerComm.Send(message); } }
調用方式以下所示
SendingSMS sendingSMS=new SendingSMS(); Ordering ordering=new Ordering(sendingSMS); ordering.customerComm=sendingSMS; ordering.Order("msg");
其實構造函數注入是實現DI最經常使用的方法.若是須要在每一個方法調用上傳遞不一樣的依賴關係,則可使用方法注入屬性注入的使用仍是比較少的.