2013-03-25 110 views
1

考慮下面的類層次結構在複雜層次注射運行時依賴抽象工廠

  • ClassA的需要ClassB的
  • ClassB的需要ClassC

我們得到了一個依賴關係圖如下:

ClassA --> ClassB --> ClassC 

所以如果我們使用DI,我們將ClassC和ClassB注入到ClassA中。

但是現在讓我們假設ClassC是一個運行時依賴項(例如某種策略)。建議的方式注入運行時的依賴是引入一個抽象工廠就像一個

ClassCFactory 

現在我們可以注入ClassCFactory到ClassB的,並得到如下圖

ClassA --> ClassB --> ClassCFactory 

現在我們有一個方法ClassB的其中我們可以打電話讓工廠做好工作。例如

ObjB.SelectC(MyRuntimeValue) 

但是現在在我們的應用中,我們不知道什麼ClassB的(或許還有一些涉及更多層)。一種解決方案可能是有SelectC在ClassA的

ObjA.SelectC(MyRuntimeValue) -(calls)-> ObjB.SelectC(MyRuntimeValue) 

,或者我們乾脆違反法律德米特和做類似

ObjA.ObjB.SelectC(MyRuntimeValue) 

我認爲每個人都同意,第二個解決方案是不是要走的路。但第一個解決方案也有一些缺點,特別是如果我們之間有更多的層。

我們也可以拉出工廠的一個層次來創建ClassB,但是ClassB真的是運行時的依賴關係嗎? 你建議什麼解決方案?或者它甚至是一個糟糕的課程設計?

恕我直言,總是更好地依賴於對象實際需要做的工作,而不是創建所需對象的工廠。但有了這個想法一記DI容器將是無用的...

回答

2

建議的方式注入運行時的依賴是引入一個 抽象工廠

你不一定需要一個抽象工廠在運行時注入事物。您可以使用setter注入或方法注入將簡單的依賴關係直接傳遞給對象。

當您必須生成一系列相關對象的對象時,抽象工廠纔是選項系列但直到運行時間才知道哪個系列。你的例子中沒有顯示這種情況,所以YAGNI/KISS將表示不使用它。

但是現在在我們的應用程序中,我們不知道任何關於ClassB (也許涉及到更多的圖層)。

您能否提供一些在您的情況下爲什麼會出現這種情況的詳細信息?對我來說,似乎總會有某種類型的執行上下文知道ClassB並能夠向其中注入C。不過,它不需要與將ClassB注入到A中的執行上下文相同。

IoC也被稱爲好萊塢原則 - "Don't call us, we'll call you""we"是誰以及"call you"部分發生的時間取決於您的應用程序可能會有很大差異,但沒有硬性規定。如果您擔心ObjectA可能對ClassC過於瞭解,只需將其注入委託給其他人。 DI容器可以幫助很多。

+0

好的,我會給你更具體的含義:ClassC是一個抽象類Encrytption,它對不同類型的加密有不同的實現。 ClassB是一個裝飾器,用Encryption裝飾FileStream。而ClassA是某種可序列化的對象,需要序列化一個流。 – 2013-03-26 10:43:17

+0

什麼決定使用哪種類型的加密?您可以讓ClassA的消費者決定並將3個俄羅斯娃娃放在一起(加密,FileStreeamDecorator和ClassA),或者一些外部對象可以選擇一個加密,將其放入FileStreamDecorator並將其全部傳遞給ClassA的消費者......真的取決於您的上下文。 – guillaume31 2013-03-26 11:28:52

+0

選擇正確的加密取決於我們加載或我們保存。加載時,我們詢問標題,使用哪種加密,然後我們詢問用戶密碼並開始閱讀和解密。在保存時,我們必須使用與加載時相同的加密。有一種特殊的導出方式,用戶最終可以決定使用哪種加密方式。 – 2013-03-26 11:54:56

0

我發現運行時依賴也很麻煩,我認爲抽象工廠的框架開銷是煩人的額外的代碼,我不希望存在。但是,我還沒有想到一個更好的方式來做這件事。

但是在上面的示例中,我的兩個選擇之間似乎沒有任何顯着差異。

在一種情況下,你有

ObjA.ObjB.SelectC(MyRuntimeValue) 

,並在其他你會

ObjA.ObjB.ObjC 

這些選項都具有相同的優點和缺點我的腦海裏。正如你注意到的,爲了避免違反得墨忒耳定律,你必須添加許多通過函數。這並不總是值得的,但絕對值得考慮。