接口的新理解與依賴注入


我以前對於java接口的理解,一直是覺得這個東西沒有什么太大用處,不如抽象類,可有可無的一個東西。但一個東西既然存在一定有他的意義,今天我就看到了接口的一個重要用法。

首先毋庸置疑的是,java單繼承的情況下,你只能繼承一個類,但可以實現多個接口,這也是我一直以為的接口唯一的用法:在單繼承不夠用的情況下實現其他的接口。

然后是我現在才知道的,接口里聲明的所有方法,在實現接口時都必須全部被實現——這可以強制實現該接口的類具有某一些特性。

這里舉一個例子說明:例子來自spring實戰這本書。

我們假設有一個繼承Knight接口的類:

package Knight_Quest;

public class DamselRescuingKnight implements Knight{
    private RescueDamselQuest quest;
    
    public DamselRescuingKnight(){
        this.quest = new RescueDamselQuest();
    }
    @Override
    public void embarkOnQuest() {
        quest.embark();
    }
}

這個類便有一個問題,首先該騎士與這種類型的任務綁死在了一起,也就是說這個類作為一個類復用性非常差(甚至想到於一個對象)。

由於在構造方法直接自行創建了RescueDamselQuest()對象,所以相當於該Knight只能執行這一種任務——如果一個少女需要救援,那么這個Knight就能招之而來,但是如果有惡龍需要殺掉,有圓桌會議要開,那么這位Knight也就愛莫能助了(僅僅是因為在構造方法中直接創建了某一種特定的對象,使得兩個類緊密的耦合在一起,無法分開)。更糟糕的是,在測試的時候,又會有一個新的問題——你無法保證在調用Knight類的embarkOnQuest()方法的時候,其下面的quest.embark()方法也能被正確的調用。所以這個類可以說是無法進行有效的測試。

所以我們就要使用依賴注入的思想來編寫:

我們可以創建一個Quest接口,且強制實現該接口的類(各種quest)都必須實現embark方法(這個embark方法可以根據類的不同而不同)

public interface Quest {
    public void embark();
}

public class RescueDamselQuest implements Quest{
    @Override
    public void embark() {

    }
}

然后我們對BraveKnight進行改寫:

public class BraveKnight implements Knight{
    private Quest quest;

    public BraveKnight(Quest quest){
        this.quest = quest;
    }
    @Override
    public void embarkOnQuest() {
        quest.embark();
    }
}

這樣改造過的Knight就不同了,構造方法中傳入的是Quest這一接口,這樣一來,BraveKnight能夠響應DamselRescuingQuest、DragonSlayQuet、RoundtableQuest等各種Quest接口的實現類。這時構造Knight,就不是由Knight自行創建某個對象,而是將各種quest對象作為構造器的參數傳入——這就是依賴注入的方式之一。

這里的要點是 BraveKnight 沒有與任何特定的 Quest 實現發生耦合。對它來說,被要求挑戰的任務只要實現了 Quest 接口,那么具體是哪種類型的任務就無關緊要了。 這就是 DI(依賴注入) 所帶來的最大收益——松耦合。

測試時只需要使用mock就行。


免責聲明!

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



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