依賴倒置原則和依賴注入模式


昨天讀完了程傑的《大話設計模式》。。收獲頗豐。深刻感到了設計模式的偉大。。對面向接口的編程也理解了不少。剛好看到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 接口在兩個類中都實現了。我們可以提供不同的類對象作為參數,這樣可以有不同的調用效果。我們可以使用這三種方法實現松耦合。取決於具體的情景

結論
不難吧。通過構造器注入我們就可以降低耦合度了。因此,程序員一般會使用構造器注入。當然也可以混合着使用嘛。。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM