軟件設計原則(一): 依賴倒置原則

如何不依賴代碼卻可以複用它的功能

在軟件設計中爲了建立清晰的軟件分層關係,引入了軟件分層設計,也是便於高層業務模塊依賴低層模塊。在一般的應用軟件中,策略層會依賴方法層,業務邏輯層會依賴數據存儲層。

在這裏插入圖片描述
圖1

這是我們正常的軟件設計。

但是這樣的設計會帶來一些問題。

策略層對方程層和工具層是傳遞依賴的,如果下面兩層的改動,都會對策略層產生影響,這樣導致的級聯改動非常不利用軟件的維護。

出現了上述問題,可能會想到定義策略層和工具層的接口,畢竟接口比實現更問題。

所以,會變成下面的設計關係。

在這裏插入圖片描述
圖2

Policy layer 層依賴的是方法層的 MechanismService 接口,而方法層會依賴工具層的 UtilityService 接口。這是通常的編程習慣,底層模塊有自己的接口,高層模塊依賴低層模塊提供的接口。

但是我們下面不是用這種方式,而是用依賴倒置設計原則去重構。

###依賴倒置的設計原則

按照依賴倒置原則,接口的所有權是被倒置的,也就是說,接口被定義在高層模塊,高層模塊擁有接口,低層模塊實現接口。不是高層模塊依賴低層模塊的接口,而是低層模塊依賴高層模塊的接口,從而實現依賴關係的倒置。

在這裏插入圖片描述
圖3

在上面的依賴層次中,每一層的接口都被高層模塊定義,由低層模塊實現,高層模塊完全不依賴底層模塊。這樣低層模塊的改動不會影響高層模塊,高層模塊的複用也不會完全依賴低層模塊。

使用依賴倒置實現高層模塊複用

依賴倒置原則也適用於一個類向另一個類發送消息的場景

Button 控制燈泡,按鈕按下的時候,燈泡點亮或關閉。常規的設計是,Button 類直接依賴 Lamp 燈泡類

在這裏插入圖片描述
圖4

這樣會導致問題,Button 依賴 Lamp, Lamp 的任何改動都會牽扯到 Button, 變成聯級的改動。另外,如果想要 Button 控制另外一種電器,Button 變難以重用, 以爲 Button 依賴着 Lamp.

解決辦法是將依賴中的具體實現,改成爲依賴抽象。

重構後的設計

在這裏插入圖片描述
圖5

抽象接口 ButtonServer 是屬於高層模塊 Button 的,不屬於低層模塊 Lamp。這樣就形成了依賴倒置。

Button 不會再依賴 Lamp,而是依賴抽象的 ButtonServer, 而 Lamp 是
ButtonServer 的具體實現,這樣 Lamp 的改動基本上就不會牽扯 Button。另外,如果想要重用 Button 控制其他設備, 只需要這些設備實現 ButtonServer 接口即可。

抽象工廠模式

在創建對象是,一般都會是具體實現,這樣就會形成一個依賴。這時,可以選擇用抽象工廠模式來解決代碼依賴的問題。

在這裏插入圖片描述
圖6

Application 通過調用 ServiceFactory接口的 makeService 方法。這個方法由 ServiceFactoryImpl 類具體提供,該方法初始化一個 ConcreteImpl 類的實例,並且將其返回 Service 類型返回。

圖6中間的虛線代表着軟件架構中的抽象層與具體實現層的邊界。所有跨越這條邊界源碼級別的依賴關係都應該是單向的,即具體實現層依賴抽象層。

抽象接口層包含了應用的所有高階業務規則,具體實現層則包括了這些業務規則需要做的具體操作及其相關的細節信息。

圖6中控制流跨越邊界(虛線)的方向與源代碼依賴關係跨越該邊界的反向相反,源代碼依賴用於是控制流方向反向,這就是依賴倒置。

參考

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章