2008-10-01 26 views
15

我一直在向我的代碼中添加依賴注入,因爲它通過代碼更容易通過代碼進行單元測試。依賴注入是否打破了Demeter法

但是,我要求我的呼叫鏈上的對象具有對呼叫鏈更下方對象的知識。

這是否違反了德米特法?如果是這樣嗎?

例如:A類對接口B有依賴性,要使用的接口的實現注入到類A的構造函數中。任何想要使用類A的人都必須具有對B.可以直接調用它的方法意義並且知道它的子組件(接口B)

維基百科對德米特的定律說:「基本概念是一個給定的對象應儘可能少地假設結構或其他任何東西(包括其子組件)的屬性。「

+1

你可以發佈一些示例代碼?如果你在做foo.bar().baz(),那麼是的,你打破了德米特法。你是說你最終這樣做? – asterite 2008-10-01 22:32:40

回答

11

依賴注入CAN可以打破得墨忒耳定律。如果你強迫消費者注入依賴關係。這可以通過靜態工廠方法和DI框架來避免。

您可以通過設計對象的方式來設計對象,以便它們需要傳遞依賴關係,並且同時具有使用它們的機制,而無需顯式執行注入(工廠函數和DI框架)。

+0

我認爲你釘了它。對這個問題的其他一些答案並不關注提問者的具體情況。 – moffdub 2008-10-02 00:11:53

1

它是否違法?
嚴格地說,我認爲它的確如此。
重要嗎?
違反法律的主要危險是你讓你的代碼變得更脆弱。
如果你真的保持在測試中,看起來危險並不算太壞。
緩解
我對Law of Demeter的理解是,它後面可以有防止直接調用對象的「包裝方法」。

3

它是如何打破它? DI完全適合最不瞭解的想法。 DI給你低耦合 - 對象相互之間的被動性較低。

援引百科:

...的對象A可以請求一個服務(呼叫 的方法)的對象實例B的,但 對象的對象A不能「通過到達」 B來訪問尚未另一個對象...

通常DI的工作方式完全相同,即使用注入組件提供的服務。如果你的對象試圖訪問某些B的相關性,即它知道很多關於B - 這是導致高耦合並打破DI

的想法

但是我需要在對象更高 我的調用鏈有 知識進一步向下呼叫鏈的對象

一些示例?

2

如果我正確地理解了你,這不是由於使用依賴注入引起的,它是由使用模擬策略引起的,你可以指定你期望的方法創建的函數調用。在許多情況下,這是完全可以接受的,但顯然這意味着如果您已指定了您認爲應該執行的操作,則必須知道所調用的方法。

寫好軟件需要平衡權衡。隨着實施變得更加完整,它變得更加不一致。你必須決定這些不一致所產生的風險以及它們是否值得他們的存在所創造的價值。

1

Demeter規則指定對象O的方法M可以調用M中創建/實例化的對象的方法。但是,沒有任何內容指定如何創建這些對象。我認爲使用中間對象來創建這些對象是完全正確的,只要該對象在生活中的目的僅僅是這個目的 - 代表您創建其他對象。從這個意義上說,DI並不違反德米特法則。

0

取決於:-)

我想最多的回答是不正確的,甚至有很多的代碼使用依賴注入和注入高層次對象的框架。然後你會得到很多依賴關係的意大利麪條代碼。

依賴注入最適合所有會污染對象模型的東西,例如ILogger。如果您確實注入了業務對象,請儘可能確保其處於最低級別,並儘可能通過傳統方法。如果它變得混亂,只能使用依賴性注入。

0

在我添加我的答案之前,我必須有資格。面向服務的編程建立在OOP原則和使用OO語言之上。此外,SOA遵循控制反轉和SOLID原則的牙齒。所以很多面向服務的程序員肯定會到達這裏。所以,這個答案適用於面向服務的程序員,因爲SOA是建立在OOP之上的。這並沒有直接回答OP的例子,但是從SOA Perspective回答了這個問題。

一般來說,德米特法不適用於面向服務的體系結構。對於OO,Demeter法則在OOP中討論具有屬性和方法的「豐富對象」,並且其屬性也可能具有方法。使用OOP豐富模型,可以通過一系列對象和訪問方法,屬性,屬性方法,屬性屬性方法等來實現。但是在面向服務的編程中,數據(屬性)與流程(方法)。您的模型(主要)僅具有屬性(肯定不會依賴),並且您的服務僅具有其他服務的方法和依賴關係。

在SOP中,您可以隨時查看模型的屬性以及屬性的屬性。你永遠不能訪問你不應該使用的方法,只能訪問數據樹。但是服務呢?德米特法律適用於那裏嗎?

是的,德米特法可以適用於SOP服務。但是,法律最初是爲OOP中的Rich Models設計的。儘管適用於服務的法律可以,適當的依賴注入自動實現Demeter法則。從這個意義上講,DI不可能違反法律。

在對Mark Roddy的有限反對中,我找不到任何可以在同一句話中合法地談論依賴注入和「消費者」的情況。如果通過「消費者」你是指一個正在消耗另一個階級的階級,那是沒有道理的。使用DI,你將有一個組合根組成你的對象圖,一個類應該永遠不會知道另一個類甚至存在。如果「消費者」是指程序員,那麼他們將如何被迫「做注射」。程序員是必須創建組合根的人,所以他們必須進行注入。程序員不應該將「注入」作爲一個類中的實例化來消耗另一個類。

請仔細閱讀下面的例子顯示實際獨立的解決方案,它們的引用和實現代碼:

In SOA, DI doesn't allow breaking of LoD

在右上方,我們有「芯」。 NuGet和NPM上的很多軟件包都有一個「核心」項目,它具有模型,接口,甚至可能默認實現。 Core永遠不應該依賴任何外部的東西。

在左上方,我們有一個Core的外部實現。實施取決於核心,因此有它的知識。

在左下方,我們有一個獨立的域。該域有一些依賴於某些實現的核心,但不需要知道實現

這就是我指出域和實現都不知道彼此存在的地方。有一個0%的機會可能達到(或超越)另一個,因爲他們甚至不知道它們存在。域只知道有一個契約,並且它可以以任何方式通過注入到其中的任何方式使用這些方法。

左下角是組合根或入口點。這也被稱爲應用程序的「Front Boundary」。應用程序的根目錄知道它的所有組件,只不過是進行輸入,確定要調用的對象,組合對象並返回輸出。換句話說,它只能告訴域名「在這裏,用它來履行你的ICalculateThings合同,然後給我CalculateTwoThings的結果。

確實有一種方法可以將所有東西都粉碎成同一個項目,做具體實例的服務,使你的依賴公共屬性而不是私人領域,仍然做依賴注入(可怕),然後讓服務調用依賴關係的依賴。但是這將是糟糕的,好吧,你必須努力這些項目可能存在於一個解決方案中(只要架構師控制參考架構),並且可能會有更多的簡化。但是,圖像中的分離真的很明顯系統必須對其部件有一點認識。只有構圖根(入口點,前邊界)需要知道這些部分。結論(TL; DR;):在Oldskewl OOP中,模型是豐富的,Demeter法則可以通過查看模型模型來輕鬆地打破訪問他們的方法。但是在Newskewl SOP(建立在OOP原則和語言基礎上)中,數據與流程分離。所以你可以隨意查看模型的屬性。然後,對於服務來說,依賴關係始終是私有的,除了抽象,合約,接口告知的內容之外,什麼都不知道。