昨天,我們認識了程式碼之間的依賴,以及依賴所造成的耦合和如何解耦合;今天,我們要來認識依賴的方向性。
指的是在軟體系統中,模塊、類或組件之間的依賴關係是單向的,即某個模塊依賴於另一個模塊,而不是反過來。這意味著一個模塊(或類、組件)在其功能實現中需要引用或調用另一個模塊的功能,而被引用的模塊不依賴於引用它的模塊。
關於哪個模塊是“上游”(依賴者)和哪個模塊是“下游”(被依賴者)的問題。通常情況下,上游模塊需要下游模塊提供某些功能、數據或服務,因此它們依賴於下游模塊。
在軟體設計和架構中,管理依賴的方向性是重要的,因為它可以影響系統的可維護性、擴展性和靈活性。正確的依賴方向可以降低模塊之間的耦合度,使系統更容易理解和修改。
反轉依賴方向是一種常見的策略,它可以通過使用接口、抽像類、依賴注入等技術來實現。這種策略的目標是使高層模塊不依賴於底層模塊的具體實現細節,而是依賴於抽像或接口,從而實現了依賴關係的反轉。
經由依賴反轉方式,Wheel
實際上可以依賴於Gear
或ratio
,計算gear_inches
仍然需要Gear
和Wheel
之間的合作,這樣的改動並不影響app的運作。
class Gear
attr_reader :chainring, :cog
def initialize(chainring, cog)
@chainring = chainring
@cog = cog
end
def gear_inches(diameter)
ratio * diameter
end
def ratio
chainring / cog.to_f
end
#...
end
class Wheel
attr_reader :rim, :tire, :gear
def initialize( rim, tire, chainring, cog)
@rim = rim
@tire = tire
@gear = Gear.new(chainring, cog)
end
def diameter
rim + (tire * 2)
end
def gear_inches
gear.gear_inches(diameter)
end
#...
end
Wheel.new(26, 1.5, 52, 11).gear_inches
物件必須依賴那些變化少於他們自身的事物,而依賴會體現在以下三個簡單的程式碼概念上
理解變化的可能性
有些類別比其他類別更容易發生變化。這個概念不僅適用於自己編寫的應用程式碼,還適用於使用但未編寫的代碼,包括Ruby基本類和其他框架的程式碼。幸運的是,Ruby基本類別的變化通常很少。無論類別來自哪裡,應用程式中的每個類別都可以進行分級。分級的依據是類別相對於其他類別發生變化的可能性,在選擇依賴方向時,這種分級是重要的依據,要考慮類別的相對穩定性是非常重要的。
區別具體與抽象
這裡所用到的「抽象」 ( abstract) 即指的是「從某種特定實例裡分離出來的內容」。 這個概念是程式碼的抽象,而不是特定的技術限制。這種抽象性允許程式碼更加通用,不依賴於特定的實現細節。
在靜態類型語言中,實現相同抽象所需的操作可能更複雜。你需要定義一個接口,將抽象的屬性或方法包含在接口 中,然後告訴類別它們實現了這個接口。這使得抽象更加明確和有目的。通過依賴注入等技術,可以實現抽象,使代碼更具通用性和靈活性。
在Ruby中,創建抽象更加直觀,但在靜態類型語言中也是有目的的,用於明確定義接口和降低依賴關係,找到具重 要性的依賴關係,抽象的美妙之處在于它代表著共同和穏定的性質。
避免使用依賴沉重負擔的類別
找到具重要性的依賴關係
最後總結各種可能組合於此圖,橫軸表示的是需求變化的可能性,縱軸則為依賴的數量。可以對比此圖去檢視一下自己目前的應用程式位在哪個區域,依賴於那些變化情況比你所做的修改還要少的事物,即代表本節的所有概念。
(圖片拍攝自書籍:Practical Object-Oriented Design in Ruby: An Agile Primer)
管理依賴關係是建立可適應於未來的應用程式的核心,注入依賴關係可以建立鬆散耦合的物件,將依賴關係隔離起來,可以讓物件快速地適應意想不到的變化。依賴於抽象則可以降低面對這些變化的可能性。
參考資料: