2013-01-06 32 views
4

我正在嘗試編寫使用依賴注入的代碼,以允許嘲笑並擁有更清晰,更明確的設計。OOP - 嵌套對象依賴關係的長鏈是否爲反模式?

我經常發現自己遇到了一個我認爲很常見的問題,但我還沒有找到任何幫助我克服它的問題。

問題是對象A依賴於B,B依賴於C,C依賴於D等等,因此鏈中可能有很多很多鏈接。

看來,要在這裏實施依賴注入,A必須在它的構造函數(或BFactory,CFactory等)中請求一個B,一個C,一個D等,以創建它們所依賴的實例)。我認爲,爲了論證,依賴關係不是可選的或者不適用於特定的方法,使得setter注入或方法參數注入不合適。

這表明對我來說,依賴對象的長鏈是反模式。從抽象意義上講,它與箭頭反模式有一些共同之處。從屬對象的長鍊形成一個箭頭形的序列圖。或許,那麼我應該避免這種做法,並遵循「扁平化比嵌套更好」的「Python的禪」中的建議。這表明一種設計,其中主程序創建兩個或三個對象,它們協作併產生返回到主程序的結果,然後再創建另外兩三個對象來完成下一個工作階段,等等。

我感覺這種代碼很容易理解和調試,也很容易進行依賴注入。但它似乎違背了Tell Do not Ask原則,並使主程序太胖。我喜歡主體非常小而明顯的想法,它不需要單元測試。告訴別別問我說,如果一切以A開頭並以A結尾,那麼這是A的責任。假設A是一位客戶,並且客戶擁有開始結算流程所需的數據以及最終發票需要發送到的電子郵件地址。那麼看起來A應該自己完成工作(主要可以調用Customer.billYourself()),而不是通過給主要的一系列發票和電子郵件地址將可靠性返回給main。

因此,我應該避免依賴鏈,讓DI更容易,或者因爲Tell Do not Ask而擁抱它們嗎?

+1

這是一個有趣但很難回答的問題,沒有一個具體的例子來談論。由於設計哲學非常不同,可能會比事實多一點意見。 –

+0

您的評論讓我意識到我正在使用的所有示例都在遺留代碼中,我正在重構可測試性。如果我發佈它們,一般糟糕的設計會導致更多的分心而不是澄清。我會嘗試去思考一個問題O' – naomi

+1

好的,所以我試圖想到一種情況,我會試圖在一個新的應用程序中使用這樣的長鏈,我想不出一個。這可能是因爲它們是反模式,只會出現在有其他問題的應用程序中。 – naomi

回答

4

類有許多依賴項。這只是生活中的一個事實。但它是這些類如何相互依賴使整個事情好壞。

您應該閱讀關於Stable Dependencies Principle。如果按照這個規則,依賴關係的數量不應該是一個問題:

包之間的依賴關係在設計中應在 方向的套餐的穩定性。一個包只應該依賴於比它更穩定的包。

有很好的相關性,而且也有不好的依賴關係:

因此,我們可以說,一個「好依賴」是在 一些具有低揮發性的依賴。依賴關係的目標越不穩定,依賴關係越「良好」。同樣的道理, 「不良依賴」依賴於易變的東西。依賴關係的目標越不穩定,依賴關係越是「不好」。

構建您的應用程序以具有良好的依賴關係。

+2

我明白這個原則,但我不明白它與我的問題有何關係。問題是不得不將C和D傳遞給A的構造函數,因爲A不直接與任何一方合作,而是將它們傳遞給B,B將C傳遞給C以供C使用。不管穩定的方向如何,A不得不知道D的封裝嗎?如果C停止要求D,則A必須改變。 C是否需要D是A不應該關心的實現細節。 – naomi

+0

A是否對C做任何事情?如果不是,那麼是的,它打破封裝,讓一個類取決於某個東西將它傳遞給另一個類是不好的。除了構造函數注入之外,您可以使用DI容器,並讓每個類從中獲取所需的內容。 –

+0

謝謝 - 這很有道理。 (我自己以前的評論沒有,現在我想到了。)可悲的是我不能在這個項目上使用DI容器。但我認爲可以用工廠來完成。如果A需要C來創建一個B,那麼A可以要求一個BFactory,並且BFactory可以通過創建一個C來啓動。不像容器那樣光滑,但仍然是封裝和可嘲諷的...... – naomi