發表文章

重新理解Law of Demeter

最近開始繼續拜讀Uncle Bob的大作Clean Code,讀到第六章講述Law of Demeter的部分時,發現自己其實根本就沒有真正地理解過它的含義,也因此沒有辦法抱持著足夠的意識在自己平日撰寫的程式中。 Law of Demeter (LoD),又稱為Least Knowledge,其目的是為了儘可能地減少class之間的耦合度,使得在日後替換implementation時,能降低系統中其它程式修改的需要。 根據Clean Code [1],LoD要求一個class所能引用的method來源只能是下列4種: 1. class自身 2. 在method裡面創建的物件 3. 作為method參數傳遞進來的物件 4. class自身的內部物件 也就是,一個class A只能使用跟它有直接關聯性的class B的method。如果A想要透過class B來取用class C所提供的method,那麼A不應該直接藉由B拿到class C的物件來呼叫C的method,因為這是class B的內部結構,A去了解B的實作細節就破壞了B的封裝。所以我們就需要思考B要怎麼提供method讓A能夠間接使用C的method。 Bad Smell? 連續以dot運算來串接而成的鏈式呼叫 (又稱為train wreck),常常可能是違反LoD的bad smell。 以Clean Code中的例子來說: 這段程式想要透過ctxt物件來找出output目錄,所以它先取得了Options物件,再透過Options物件取得ScratchDir物件,再透過ScratchDir物件繼而取得output目錄。使用ctxt的method知道了太多它不應該知道的細節了,因為它需要去了解有哪些物件需要逐層被取出,然後才能找到output目錄,所以這樣的鏈式呼叫會與執行它的上層程式產生緊密的耦合度,日後不好修改。 對於這樣的狀況,我們就需要去思考寫這段程式的目的是為了解決什麼問題,是不是根本可以換個方式設計。回到剛剛Clean Code的例子,該段鏈式呼叫的最終目的其實是想要為output目錄下的某檔案創建一個BufferedOutputStream。所以呼叫端的那串鏈式呼叫可以被替換為: 把取得SratchDir()和absolute path的邏輯封裝在cre