天天看點

《Android 源碼設計模式解析與實戰》——第1章,第1.4節讓項目擁有變化的能力——依賴倒置原則

本節書摘來自異步社群《android 源碼設計模式解析與實戰》一書中的第1章,第1.4節讓項目擁有變化的能力——依賴倒置原則,作者 何紅輝 , 關愛民,更多章節内容可以通路雲栖社群“異步社群”公衆号檢視

1.4 讓項目擁有變化的能力——依賴倒置原則

依賴倒置原則英文全稱是dependence inversion principle,縮寫是dip。依賴倒置原則指代了一種特定的解耦形式,使得高層次的子產品不依賴于低層次的子產品的實作細節的目的,依賴子產品被颠倒了。這個概念有點不好了解,這到底是什麼意思呢?

依賴倒置原則有以下幾個關鍵點:

(1)高層子產品不應該依賴低層子產品,兩者都應該依賴其抽象;

(2)抽象不應該依賴細節;

(3)細節應該依賴抽象。

在java語言中,抽象就是指接口或抽象類,兩者都是不能直接被執行個體化的;細節就是實作類,實作接口或繼承抽象類而産生的類就是細節,其特點就是,可以直接被執行個體化,也就是可以加上一個關鍵字new産生一個對象。高層子產品就是調用端,低層子產品就是具體實作類。依賴倒置原則在 java語言中的表現就是:子產品間的依賴通過抽象發生,實作類之間不發生直接的依賴關系,其依賴關系是通過接口或抽象類産生的。這又是一個将理論抽象化的執行個體,其實一句話就可以概括:面向接口程式設計,或者說是面向抽象程式設計,這裡的抽象指的是接口或者抽象類。面向接口程式設計是面向對象精髓之一,也就是上面兩節強調的抽象。

如果類與類直接依賴于細節,那麼它們之間就有直接的耦合,當具體實作需要變化時,意味着要同時修改依賴者的代碼,這限制了系統的可擴充性。在1.3節的圖1-3中,imageloader直接依賴于memorycache,這個memorycache是一個具體實作,而不是一個抽象類或者接口。這導緻了imageloader直接依賴了具體細節,當memorycache不能滿足imageloader而需要被其他緩存實作替換時,此時就必須修改imageloader的代碼,例如:

随着産品的更新,使用者發現memorycache已經不能滿足需求,使用者需要小民的imageloader可以将圖檔同時緩存到記憶體和sd卡中,或者可以讓使用者自定義實作緩存。此時,我們的memorycache這個類名不僅不能夠表達記憶體緩存和sd卡緩存的意義,也不能夠滿足功能。另外,使用者需要自定義緩存實作時還必須繼承自memorycache,而使用者的緩存實作可不一定與記憶體緩存有關,這在命名上的限制也讓使用者體驗不好。重構的時候到了!小民的第一種方案是将memorycache修改為doublecache,然後在doublecache中實作具體的緩存功能。我們需要将imageloader修改如下:

在程式中我們将memorycache修改成doublecache,然後修改了imageloader中緩存類的具體實作,輕輕松松就滿足了使用者需求。等等!這不還是依賴于具體的實作類(doublecache)嗎?當使用者的需求再次變化時,我們又要通過修改緩存實作類和imageloader代碼來實作?修改原有代碼不是違反了1.3節中的開閉原則嗎?小民突然醒悟了過來,低下頭思索着如何才能讓緩存系統更靈活,擁抱變化……

當然,這些都是在主管給出圖1-2以及相應的代碼之前,小民體驗的煎熬過程。既然是這樣,那顯然主管給出的解決方案就能夠讓緩存系統更加靈活。一句話概括起來就是:依賴抽象,而不依賴具體實作。針對于圖檔緩存,主管建立的imagecache抽象,該抽象中增加了get和put方法用以實作圖檔的存取。每種緩存實作都必須實作這個接口,并且實作自己的存取方法。當使用者需要使用不同的緩存實作時,直接通過依賴注入即可,保證了系統的靈活性。我們再來簡單回顧一下相關代碼。

在這裡,我們建立了imagecache抽象,并且讓imageloader依賴于抽象而不是具體細節。當需求發生變化時,小民隻需要實作imagecahce類或者繼承其他已有的imagecache子類完成相應的緩存功能,然後将具體的實作注入到imageloader即可實作緩存功能的替換,這就保證了緩存系統的高可擴充性,有了擁抱變化的能力,這就是依賴倒置原則。從上述幾節中我們發現,要想讓系統更為靈活,抽象似乎成了我們唯一的手段。

繼續閱讀