依賴倒置原則就看這篇,7張圖解徹底吃透,架構設計築基必知必會

帶你聊技術發表於2023-11-01

來源:mikechen的網際網路架構

依賴倒置是確保架構設計靈活性、擴充套件性的重要原則。

把依賴方向搞反,是經常出現的典型錯誤。依賴關係沒處理好,就會導致一個小改動,影響一大片。

結構化的程式設計思路,是自上而下進行功能分解,再按照分解結果進行組合的。這個思路很自然就延續到了很多人的程式設計習慣中。

依賴倒置原則就看這篇,7張圖解徹底吃透,架構設計築基必知必會

本文,我們將透過手工圖解、原始碼示例,來全面解析依賴倒置原則。

依賴倒置原則就看這篇,7張圖解徹底吃透,架構設計築基必知必會

大家好,我是 mikechen。

依賴倒置是良好架構設計的基石,社/校招面試常問,必知必會非常重要。為方便大家系統學習,我已將本文歸納到《阿里架構師進階專題合集》。需要的同學,拉到文末自取。


依賴倒置原則就看這篇,7張圖解徹底吃透,架構設計築基必知必會

01
   什麼是依賴倒置原則

依賴倒置原則(DIP),英文全稱 Dependency Inversion Principle。

顧名思義,就是將傳統的依賴關係顛倒過來,讓高層模組和底層模組都依賴於抽象介面。

依賴倒置之所以被提出,是源自它所提倡的軟體設計原則。


02
  依賴倒置的 UML 類圖

依賴倒置原則就看這篇,7張圖解徹底吃透,架構設計築基必知必會


03
  依賴倒置的核心思想

依賴倒置原則的兩個核心思想:

1) 高層模組不應依賴於底層模組,高層模組、底層模組都應依賴於抽象

2) 抽象不應該依賴於細節,細節應該依賴於抽象

這意味著,

在軟體設計中,應該使用抽象類、介面或抽象方法等抽象層,來定義模組之間的通訊介面。而具體實現,應該依賴於這些抽象。

一圖釋義:

依賴倒置原則就看這篇,7張圖解徹底吃透,架構設計築基必知必會

 抽象的關鍵在於:

  • 它提供了一種通用的、高層次的方式,來定義模組之間的介面和互動,而不關心具體的實現。


  • 高層模組將依賴於這個抽象,而不是直接依賴於底層模組的具體細節。


在依賴倒置原則中,抽象可以透過抽象類、介面或抽象方法來實現。

 

04
  依賴倒置原則的作用

依賴倒置改變了傳統的依賴關係

依賴倒置從具體細節轉移到了抽象上,極大提高了系統的靈活性、可維護性和可擴充套件性。

在傳統的依賴關係中,高層模組直接依賴於底層模式的實現細節。

依賴倒置原則就看這篇,7張圖解徹底吃透,架構設計築基必知必會

高層模組需要了解並依賴於底層模組的內部細節,包括其資料結構、演算法和邏輯。

由於高層模組與底層模式是一種緊耦合的關係,當底層模組結構發生變化時,高層就需要隨之改變。

一個小的變更,可能導致大範圍的程式碼修改和測試。

傳統依賴的架構設計很不合理,系統結構太剛性,難以維護及擴充套件。

傳統依賴 VS 依賴倒置:

依賴倒置原則就看這篇,7張圖解徹底吃透,架構設計築基必知必會


05
  依賴倒置的例項

再來對比下傳統依賴、依賴倒置的實現。

假設:

現在你需要實現一個麵包店,你第一件想到的事情是什麼?

我想到的是一個麵包店,裡面有很多具體的麵包。

例如:法棍麵包、全麥麵包、白麵包、牛角麵包、蕎麥麵包、法式麵包、甜甜圈麵包、裸麥麵包。

傳統依賴關係:

麵包店就是上層模組,麵包是下層模組。如圖:

依賴倒置原則就看這篇,7張圖解徹底吃透,架構設計築基必知必會

麵包店(Bakery)直接依賴於具體的麵包型別(FrenchBaguette 和 WholeWheatBread),這是傳統的依賴關係。

當增加底層模組(麵包型別)時,對高層模組(麵包店)有何影響呢。

















































class Bakery {    private FrenchBaguette frenchBaguette;    private WholeWheatBread wholeWheatBread;
   public Bakery() {        frenchBaguette = new FrenchBaguette();        wholeWheatBread = new WholeWheatBread();        // 初始化具體的麵包型別    }
   public void serveBread() {        frenchBaguette.serve();        wholeWheatBread.serve();        // 提供其他具體面包型別    }}
class FrenchBaguette {    public void serve() {        System.out.println("法棍麵包供應中");    }}
class WholeWheatBread {    public void serve() {        System.out.println("全麥麵包供應中");    }}
// 假設現在需要新增一種新的麵包型別,例如牛角麵包class Croissant {    public void serve() {        System.out.println("牛角麵包供應中");    }}
public class Main {    public static void main(String[] args) {        Bakery bakery = new Bakery();        bakery.serveBread();
       // 現在需要新增新的麵包型別(牛角麵包)        Croissant croissant = new Croissant();        croissant.serve();
       // 這裡需要手動修改Bakery類,將新的麵包型別整合進去    }}

如果要新增新的麵包型別,例如 Croissant,就需要修改 Bakery 類的程式碼,將新的麵包型別整合進去。

顯然,這種方式不夠靈活,增加了維護成本和程式碼的脆弱性。

依賴倒置:

我們不希望讓麵包店理會這些具體類,於是,重新設計麵包店:

  • 建立一個抽象的麵包介面,讓麵包店依賴於這個抽象介面,不再依賴於具體的麵包種類。


  • 既然法棍麵包、牛角麵包、白麵包等都是麵包,就讓它們共享一個麵包介面,抽象化一個麵包類。


如圖所示:

依賴倒置原則就看這篇,7張圖解徹底吃透,架構設計築基必知必會

麵包店是高層模組,麵包類是抽象介面,而各種具體的麵包是底層模組。

現在,我們需要增加新的麵包型別(底層模組)。

























































// 麵包介面,作為高層模組和底層模組之間的抽象interface Bread {    void serve();}
// 具體面包類實現麵包介面,作為底層模組class FrenchBaguette implements Bread {    public void serve() {        System.out.println("法棍麵包供應中");    }}
class WholeWheatBread implements Bread {    public void serve() {        System.out.println("全麥麵包供應中");    }}
// 假設需要新增一種新的麵包型別,例如牛角麵包class Croissant implements Bread {    public void serve() {        System.out.println("牛角麵包供應中");    }}
// 高層模組,麵包店class Bakery {    private Bread bread;
   public Bakery(Bread bread) {        this.bread = bread;    }
   public void serveBread() {        bread.serve();    }}
public class Main {    public static void main(String[] args) {        // 建立麵包店並提供不同型別的麵包        Bread frenchBaguette = new FrenchBaguette();        Bread wholeWheatBread = new WholeWheatBread();
       Bakery bakery1 = new Bakery(frenchBaguette);        bakery1.serveBread();
       Bakery bakery2 = new Bakery(wholeWheatBread);        bakery2.serveBread();
       // 新增的麵包型別(牛角麵包)不會影響麵包店        Bread croissant = new Croissant();        Bakery bakery3 = new Bakery(croissant);        bakery3.serveBread();    }}

麵包店(Bakery)依賴於抽象的 Bread 介面,而不依賴於具體的麵包型別。

當需要新增一種麵包型別(例如Croissant)時,不會對高層模組(Bakery)產生影響,因為高層模組依賴於抽象介面。

對於具體的實現類我們不管,只要介面的行為不發生變化,增加新的麵包類後,上層服務不用做任何的修改。

這樣的設計降低了層與層之間的耦合,能很好地適應需求的變化,從而提高了系統的可擴充套件性和可維護性。


總結
  

依賴倒置原則透過抽象(介面或抽象類),讓各個類或模組的實現彼此獨立,不互相影響,實現模組間的松耦合。

依賴倒置原則的核心思想是:高層模組不應依賴於低層模組,兩者都應該依賴於抽象。抽象不應該依賴於細節,細節應該依賴於抽象。

遵循依賴倒置原則,透過降低層與層之間的耦合,可以很好地適應需求的變化,提高了系統的可擴充套件性和可維護性。

建議收藏備用,划走就再也找不到了。

依賴倒置是良好架構設計的基石,社/校招面試也常問,必知必會非常重要。


來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/70024922/viewspace-2992214/,如需轉載,請註明出處,否則將追究法律責任。

相關文章