解讀依賴倒置原則 。什么是依賴倒置?誰和誰的依賴倒置了?
什么是依賴倒置?
按照定義來說,它有兩條:
- 高層模塊不應該依賴于低層模塊。兩者都應該依賴于抽象。
- 抽象不應該依賴于細節。細節應該取決于抽象。
參見 OODesign
看定義似乎并不能解決“倒置”的疑問。
誰和誰的依賴倒置了?
定義的第一條說:高層模塊不應該依賴于低層模塊。兩者都應該依賴于抽象。
這并不能解決“倒置”的疑問,因為它說的是該原則的代碼層級的設計,它引入了一個抽象的中間層。
看第二句:抽象不應該依賴于細節。細節應該取決于抽象。
這里解釋了倒置,從抽象依賴于細節的關系倒置為細節依賴于抽象。
什么是細節,什么是抽象?
在低層模塊到高層模塊的代碼設計中,高層模塊的實現依賴于低層模塊提供的功能。
業務需求作為抽象的事物依賴于有著細節的功能,只有低層模塊完成了,高層模塊才能被實現。
隨著需求的增長與變化,功能越來越多,高層模塊的代碼會隨著低層模塊的變化而被不斷地修改,以致越來越難以維護。
是時候改變了,怎么改變呢?
思考一下:
- 需求的實現是可以預見的,只要在需要的時候提供適用的功能即可。
- 這些功能的設定可以由高層模塊來決定,由低層模塊來實現。
這個時候高層模塊就不再依賴低層模塊的具體實現了,它只依賴自己對功能的設定。
可是低層模塊怎么知道高層模塊需要的功能是如何設定的呢?
這需要一個獨立的約定,引入中間層就能解決。
看一個小劇場:
高層模塊需要文件操作的功能,原來他都是自己干,后來越來越忙,就招人來干;
但是業務不斷擴張,找到的人不能勝任工作了,他要么自己親自下場培訓要么親自找人把原來的換掉。
到后來他不勝其煩,直到聽說有專門提供人才尋訪服務的獵頭。
高層模塊找到獵頭說:我要文件操作的功能,幫幫我;
獵頭:給我你的要求,我來找人。
高層模塊:能讀取、寫入、覆蓋、追加。
獵頭:好的!低層模塊甲,這個活你能不能做?
低層模塊甲:可以。
獵頭帶著甲找到高層模塊,然后交差了。
過來一段時間...
高層模塊:當前我們只能進行本地文件操作,你能不能找個會遠程文件操作啊?獵頭。
獵頭:可以
低層模塊乙:等待多時了,嘿嘿。
獵頭帶著乙找到高層模塊把甲替換了,然后交差了。
這個時候,高層模塊對低層模塊只管按照約定來差遣,不需要與之溝通。
當不滿意或者希望找一個更有本事的文件操作員的時候,只需要和獵頭溝通,由獵頭來尋人。
看完小劇場,將其對應到代碼中:
在設計業務代碼的時候,高層模塊不需要依賴特定的低層模塊來設計,將要使用的功能抽離出來,并設定功能的設計標準,也就是由高層模塊決定做什么。
而低層模塊決定怎么做,它按照高層模塊設定的標準來實現具體的功能細節,交由高層模塊使用。
在 OOP 中,我們通過接口來定義功能,提通過類實現接口的方式來實現功能的細節。
這個時候即使還沒有編寫任何提供功能實現的低層模塊代碼,我們高層模塊的代碼也能完成。
這樣的代碼結構,實現了“高層模塊不應該依賴于低層模塊,兩者都應該依賴于抽象”的定義。
而將業務需要的功能從業務代碼中抽離出來,成為中間層,實現了從 “業務需求依賴于既定的功能” 到 “業務邏輯與既定功能的實現都依賴于抽象的中間層”的轉換,對應了“抽象不應該依賴于細節。細節應該取決于抽象”的定義。
從抽象依賴具體到具體依賴抽象才是“依賴倒置”的真實含義,說的是“抽象和具體”的依賴關系,而不是原先的高層模塊與低層模塊之間依賴關系的變化,因為按照 DIP 原則設計代碼結構后,二者已經實現了解耦。
過去我一直糾結這兩個代碼層的關系,而忽略了定義的第二句。光想著這倆都解耦了,沒直接依賴關系了,還倒置個什么呀?想了好久才明白人家說的和我想不是一回事兒,觀察角度錯了。
概念不能憑空被解讀,這些設計模式、設計原則是從實踐中總結的,通過簡單的描述或簡單的示例代碼并不能很好的理解,非得是實踐才能出真知。

浙公網安備 33010602011771號