依賴倒置原則(DIP)

依賴倒置原則定義

依賴倒置原則(Dependence Inversion Principle ,DIP)定義如下:

High level modules should not depend upon low level modules,Both should depend upon abstractions.Abstractions should not depend upon details.Details should depend upon abstracts.

翻譯過來為:

  • 高層模塊不應該依賴低層模塊,兩者都應該依賴抽象
  • 抽象不應該依賴細節(jié)
  • 細節(jié)應該依賴抽象

也可以說高層模塊,低層模塊,細節(jié)都應該依賴抽象

每一個邏輯的實現(xiàn)都是由顆粒原子邏輯組成的,顆粒原子邏輯就是低層模塊,而顆粒原子邏輯組成的模塊就是高層模塊。在java語言中,抽象就是接口或抽象類,兩都都是不能直接被實例化的,細節(jié)就是實現(xiàn)類,實現(xiàn)接口或繼承抽象類而產(chǎn)生的類就是細節(jié),兩者都可以直接被實例化。

依賴倒置原則在java語言中,表現(xiàn)是:

  • 模塊間的依賴通過抽象發(fā)生,實現(xiàn)類之間不發(fā)生直接的依賴關(guān)系,其依賴關(guān)系是通過接口或抽象類產(chǎn)生的。
  • 接口或抽象類不依賴實現(xiàn)類
  • 實現(xiàn)類依賴接口或抽象類

更加精簡的定義就是“面向接口編程”—OOD(Object-Oriented Design,面向?qū)ο笤O(shè)計)的精髓之一。

依賴倒置原則的好處

采用依賴倒置原則可以減少類間的耦合性,提高系統(tǒng)的穩(wěn)定,降低并行開發(fā)引起的風險,提高代碼的可讀性和可維護性。

為什么我們要符合依賴倒置原則

我們通過一個例子說明依賴倒置原則對于開發(fā)有上面的好處。

大家都喜歡閱讀,閱讀文學經(jīng)典滋潤自己的內(nèi)心心靈,下面是小明同學閱讀文學經(jīng)典的一個類圖:

小明閱讀文學數(shù)據(jù)類圖

文學經(jīng)典的源代碼:

//文學經(jīng)典類
public class LiteraryClassic{
    //閱讀文學經(jīng)典
    public void read(){
       System.out.println("文學經(jīng)典閱讀,滋潤自己的內(nèi)心心靈");
    }
}

小明類:

//小明類
public class XiaoMing{
    //閱讀文學經(jīng)典
    public void read(LiteraryClassic literaryClassic){
        literaryClassic.read();
    }
}

場景類:

public class Client{
   public static void main(Strings[] args){
      XiaoMing xiaoming = new XiaoMing();
      LiteraryClassic literaryClassic = new LiteraryClassic();
      //小明閱讀文學經(jīng)典
      xiaoming.read(literaryClassic);
   }

}

看,我們的實現(xiàn),小明同學可以閱讀文學經(jīng)典了。

小明同學看了一段文學經(jīng)典后,忽然他想看看看小說來放松一下自己,我們實現(xiàn)一個小說類:

小說類源代碼

//小說類
public class Novel{
    //閱讀小說
    public void read(){
       System.out.println("閱讀小說,放松自己");
    }
}

現(xiàn)在我們再來看代碼,發(fā)現(xiàn)XiaoMing類的read方法只與文學經(jīng)典LiteraryClassic類是強依賴,緊耦合關(guān)系,小明同學竟然閱讀不了小說類。這與現(xiàn)實明顯的是不符合的,代碼設(shè)計的是有問題的。那么問題在那里呢?

我們看小明類,此類是一個高層模塊,并且是一個細節(jié)實現(xiàn)類,此類依賴的是一個文學經(jīng)典LiteraryClassic類,而文學經(jīng)典LiteraryClassic類也是一個細節(jié)實現(xiàn)類。這是不是就與我們說的依賴倒置原則相違背呢?依賴倒置原則是說我們的高層模塊,實現(xiàn)類,細節(jié)類都應該是依賴與抽象,依賴與接口和抽象類。

為了解決小明同學閱讀小說的問題,我們根據(jù)依賴倒置原則先抽象一個閱讀者接口,下面是完整的uml類圖:

讀者與閱讀動作解耦

IReader接口:

public interface IReader{
   //閱讀
   public void read(IRead read){
       read.read();
   }

}

再定義一個被閱讀的接口IRead:

public interface IRead{
   //被閱讀
   public void read();
}

再定義文學經(jīng)典類和小說類:
文學經(jīng)典類:

//文學經(jīng)典類
public class LiteraryClassic implements IRead{
    //閱讀文學經(jīng)典
    public void read(){
       System.out.println("文學經(jīng)典閱讀,滋潤自己的內(nèi)心心靈");
    }
}

小說類:

//小說類
public class Novel implements IRead{
    //閱讀小說
    public void read(){
       System.out.println("閱讀小說,放松自己");
    }
}

再實現(xiàn)小明類:

//小明類
public class XiaoMing implements IReader{
    //閱讀
    public void read(IRead read){
        read.read();
    }
}

然后,我們再讓小明分別閱讀文學經(jīng)典和小說:

Client:

public class Client{
   public static void main(Strings[] args){
      XiaoMing xiaoming = new XiaoMing();
      IRead literaryClassic = new LiteraryClassic();
      //小明閱讀文學經(jīng)典
      xiaoming.read(literaryClassic);

      IRead novel = new Novel();
      //小明閱讀小說
      xiaoming.read(novel);
   }

}

至此,小明同學是可以閱讀文學經(jīng)典,又可以閱讀小說了,目的達到了。

為什么依賴抽象的接口可以適應變化的需求?這就要從接口的本質(zhì)來說,接口就是把一些公司的方法和屬性聲明,然后具體的業(yè)務(wù)邏輯是可以在實現(xiàn)接口的具體類中實現(xiàn)的。所以我們當依賴對象是接口時,就可以適應所有的實現(xiàn)此接口的具體類變化。

依賴的三種方法

依賴是可以傳遞,A對象依賴B對象,B又依賴C,C又依賴D,……,依賴不止。只要做到抽象依賴,即使是多層的依賴傳遞也無所謂懼。
對象的依賴關(guān)系有三種方式來傳遞:

構(gòu)造函數(shù)傳遞依賴對象

在類中通過構(gòu)造函數(shù)聲明依賴對象,按照依賴注入的說法,這種方式叫做構(gòu)造函數(shù)注入:

構(gòu)造函數(shù)注入:

//小明類
public class XiaoMing implements IReader{
     private IRead read;
     //構(gòu)造函數(shù)注入
     public XiaoMing(IRead read){
        this.read = read;
     }

    //閱讀
    public void read(){
        read.read();
    }
}

Setter方法傳遞依賴對象

在類中通過Setter方法聲明依賴關(guān)系,依照依賴注入的說法,這是Setter依賴注入:

//小明類
public class XiaoMing implements IReader{
     private IRead read;
     //Setter依賴注入
     public setRead(IRead read){
        this.read = read;
     }

    //閱讀
    public void read(){
        read.read();
    }
}

接口聲明依賴

在接口的方法中聲明依賴對象,在為什么我們要符合依賴倒置原則的例子中,我們采用了接口聲明依賴的方式,該方法也叫做接口注入。

依賴倒置原則的經(jīng)驗

依賴倒置原則的本質(zhì)就是通過抽象(接口或抽象類)使各個類或模塊的實現(xiàn)彼此獨立,不互相影響,實現(xiàn)模塊間的松耦合。我們在項目中使用這個原則要遵循下面的規(guī)則:

  • 每個類盡量都有接口或者抽象類,或者抽象類和接口兩都具備
  • 變量的表面類型盡量是接口或者抽象類
  • 任何類都不應該從具體類派生
  • 盡量不要覆寫基類的方法
    如果基類是一個抽象類,而這個方法已經(jīng)實現(xiàn)了,子類盡量不要覆寫。類間依賴的是抽象,覆寫了抽象方法,對依賴的穩(wěn)定性會有一定的影響。
  • 結(jié)合里氏替換原則使用

里氏替換原則:父類出現(xiàn)的地方子類就能出現(xiàn)。結(jié)合本章我們得出了一個通俗的規(guī)則:接口負責定義public屬性和方法,并且聲明與其他對象的依賴關(guān)系。抽象類負責公共構(gòu)造部分的實現(xiàn),實現(xiàn)類準確的實現(xiàn)業(yè)務(wù)邏輯,同時在適當?shù)臅r候?qū)Ω割愡M行細化。

依賴倒置原則是6個設(shè)計原則中最難以實現(xiàn)的原則,它是實現(xiàn)開閉原則的重要方法,在項目中,大家只要記住是”面向接口編程”就基本上是抓住了依賴倒置原則的核心了。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容