設計模式六大原則(3):依賴倒置原則

依賴倒置原則: java

A.高層次的模塊不該該依賴於低層次的模塊,他們都應該依賴於抽象。 編程

B.抽象不該該依賴於具體,具體應該依賴於抽象。 架構

定義:高層模塊不該該依賴低層模塊,兩者都應該依賴其抽象;抽象不該該依賴細節;細節應該依賴抽象。 框架

問題由來:類A直接依賴類B,假如要將類A改成依賴類C,則必須經過修改類A的代碼來達成。這種場景下,類A通常是高層模塊,負責複雜的業務邏輯;類B和類C是低層模塊,負責基本的原子操做;假如修改類A,會給程序帶來沒必要要的風險。 編碼

解決方案:將類A修改成依賴接口I,類B和類C各自實現接口I,類A經過接口I間接與類B或者類C發生聯繫,則會大大下降修改類A的概率。 spa

       依賴倒置原則基於這樣一個事實:相對於細節的多變性,抽象的東西要穩定的多。以抽象爲基礎搭建起來的架構比以細節爲基礎搭建起來的架構要穩定的多。在java中,抽象指的是接口或者抽象類,細節就是具體的實現類,使用接口或者抽象類的目的是制定好規範和契約,而不去涉及任何具體的操做,把展示細節的任務交給他們的實現類去完成。 設計

       依賴倒置原則的核心思想是面向接口編程,咱們依舊用一個例子來講明面向接口編程比相對於面向實現編程好在什麼地方。場景是這樣的,母親給孩子講故事,只要給她一本書,她就能夠照着書給孩子講故事了。代碼以下: 繼承

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
class Book {
     public String getContent ( ) {
         return "好久好久之前有一個阿拉伯的故事……" ;
     }
}
 
class Mother {
     public void narrate ( Book book ) {
         System . out . println ( "媽媽開始講故事" ) ;
         System . out . println ( book . getContent ( ) ) ;
     }
}
 
public class Client {
     public static void main ( String [ ] args ) {
         Mother mother = new Mother ( ) ;
         mother . narrate ( new Book ( ) ) ;
     }
}

運行結果: 接口

媽媽開始講故事
好久好久之前有一個阿拉伯的故事……
開發

       運行良好,假若有一天,需求變成這樣:不是給書而是給一份報紙,讓這位母親講一下報紙上的故事,報紙的代碼以下:

1
2
3
4
5
class Newspaper {
     public String getContent ( ) {
         return "林書豪38+7領導尼克斯擊敗湖人……" ;
     }
}

 

       這位母親卻辦不到,由於她竟然不會讀報紙上的故事,這太荒唐了,只是將書換成報紙,竟然必需要修改Mother才能讀。假如之後需求換成雜誌呢?換成網頁呢?還要不斷地修改Mother,這顯然不是好的設計。緣由就是Mother與Book之間的耦合性過高了,必須下降他們之間的耦合度才行。

咱們引入一個抽象的接口IReader。讀物,只要是帶字的都屬於讀物:

1
2
3
interface IReader {
     public String getContent ( ) ;
}

Mother類與接口IReader發生依賴關係,而Book和Newspaper都屬於讀物的範疇,他們各自都去實現IReader接口,這樣就符合依賴倒置原則了,代碼修改成:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
class Newspaper implements IReader {
     public String getContent ( ) {
         return "林書豪17+9助尼克斯擊敗老鷹……" ;
     }
}
class Book implements IReader {
     public String getContent ( ) {
         return "好久好久之前有一個阿拉伯的故事……" ;
     }
}
 
class Mother {
     public void narrate ( IReader reader ) {
         System . out . println ( "媽媽開始講故事" ) ;
         System . out . println ( reader . getContent ( ) ) ;
     }
}
 
public class Client {
     public static void main ( String [ ] args ) {
         Mother mother = new Mother ( ) ;
         mother . narrate ( new Book ( ) ) ;
         mother . narrate ( new Newspaper ( ) ) ;
     }
}

 

運行結果:

媽媽開始講故事
好久好久之前有一個阿拉伯的故事……
媽媽開始講故事
林書豪17+9助尼克斯擊敗老鷹……

       這樣修改後,不管之後怎樣擴展Client類,都不須要再修改Mother類了。這只是一個簡單的例子,實際狀況中,表明高層模塊的Mother類將負責完成主要的業務邏輯,一旦須要對它進行修改,引入錯誤的風險極大。因此遵循依賴倒置原則能夠下降類之間的耦合性,提升系統的穩定性,下降修改程序形成的風險。

      採用依賴倒置原則給多人並行開發帶來了極大的便利,好比上例中,本來Mother類與Book類直接耦合時,Mother類必須等Book類編碼完成後才能夠進行編碼,由於Mother類依賴於Book類。修改後的程序則能夠同時開工,互不影響,由於Mother與Book類一點關係也沒有。參與協做開發的人越多、項目越龐大,採用依賴致使原則的意義就越重大。如今很流行的TDD開發模式就是依賴倒置原則最成功的應用。

      傳遞依賴關係有三種方式,以上的例子中使用的方法是接口傳遞,另外還有兩種傳遞方式:構造方法傳遞setter方法傳遞,相信用過Spring框架的,對依賴的傳遞方式必定不會陌生。
在實際編程中,咱們通常須要作到以下3點:

  • 低層模塊儘可能都要有抽象類或接口,或者二者都有。
  • 變量的聲明類型儘可能是抽象類或接口。
  • 使用繼承時遵循里氏替換原則。

依賴倒置原則的核心就是要咱們面向接口編程,理解了面向接口編程,也就理解了依賴倒置。

相關文章
相關標籤/搜索