昨天讀完了程傑的《大話設計模式》。。收獲頗豐。深刻感到了設計模式的偉大。。對面向接口的編程也理解了不少。剛好看到codeproject上一篇將依賴倒置的。講到了依賴注入的方式。仔細讀了一下。翻譯一遍加深認識。
高耦合的代碼隨着項目復雜性的不斷增加,最終會變成一碗碗的意大利面條啦。。二者通常是軟件設計上的問題,如果一個類對另一個類的實現了解太多。當該類改變的時候會引起更多的改變。這違反了依賴倒置原則
而松耦合的代碼設計優良。隨着時間流逝,代碼復雜兩增大,松耦合的好處會變得更加清晰,依賴注入模式是實現松耦合的一個好的辦法,本文介紹在沒有依賴注入容器的情況下實現依賴注入
GoF說了,依賴倒置的原則:
高層模塊不應依賴於低層模塊,他們都應該依賴於抽象
抽象不依賴細節,細節依賴抽象
剛開始寫依賴倒置比較難,隨着經驗增長會有所改善,通過使高層模塊依賴於抽象,依賴倒置成功解耦,依賴注入模式是該原則的一個實現。
通常我們寫出如下的代碼:
public class Email { public void SendEmail() { // code } } public class Notification { private Email _email; public Notification() { _email = new Email(); } public void PromotionalNotification() { _email.SendEmail(); } }
Notification類依賴Email類,這違反了DIP,而且當我們要發送短信/保存到數據庫的時候,我們還要改變Notification類。
我們使用抽象類/接口解耦
public interface IMessageService { void SendMessage(); } public class Email : IMessageService { public void SendMessage() { // code } } public class Notification { private IMessageService _iMessageService; public Notification() { _iMessageService = new Email(); } public void PromotionalNotification() { _iMessageService.SendMessage(); } }
IMessageService 是一個接口,而Notification 類只要調用接口的方法/屬性就可以了
同時,我們把Email對象的構造移到Notification 類外面去。
依賴注入模式可以實現。通常有三種方式
1. 構造器注入
2. 屬性注入
3. 方法注入
構造器注入
最普遍的方式,當一個類需要另一個類的依賴的時候,我們通過構造函數來提供,現在我們這樣寫
public class Notification { private IMessageService _iMessageService; public Notification(IMessageService _messageService) { this._iMessageService = _messageService; } public void PromotionalNotification() { _iMessageService.SendMessage(); } }
有幾個好處:1.構造函數實現很簡單,Notification類需要知道的很少。想要創建Notification實例的時候看構造函數就可以知道需要什么信息了。因此實現了松耦合。
屬性注入
屬性注入/setter注入比較不常見,當依賴可有可無的時候很有用。我們暴露一個可寫的屬性,允許客戶提供不同的依賴實現,比如這樣。
public class Notification { public IMessageService MessageService { get; set; } public void PromotionalNotification() { if (MessageService == null) { // some error message } else { MessageService.SendMessage(); } } }
沒有了構造函數。而用屬性來替換,在PromotionalNotifications 方法里我們需要檢查MessageService的值或者提供相應的服務。
方法注入
當依賴可以對於每個方法調用都不同的時候,我們可以通過一個方法參數來實現,比如我們的這個類還可以發送短信。我們就要使用方法注入
public class Email : IMessageService { public void SendMessage() { // code for the mail send } } public class SMS : IMessageService { public void SendMessage() { // code for the sms send } } public class Notification { public void PromotionalNotification(IMessageService _messageService) { _messageService.SendMessage(); } }
IMessageService 接口在兩個類中都實現了。我們可以提供不同的類對象作為參數,這樣可以有不同的調用效果。我們可以使用這三種方法實現松耦合。取決於具體的情景
結論
不難吧。通過構造器注入我們就可以降低耦合度了。因此,程序員一般會使用構造器注入。當然也可以混合着使用嘛。。