2013-07-19 42 views
0

我有一個業務層,其中只有一個類應該是外部世界可見的。所以,我已經把所有的班級都標記爲內部,除了那個班級。由於該類需要一些內部類來實例化,因此我需要將其他類標記爲public,其他類依賴於其他類等。所以最終幾乎所有我的內部課程都公開了。確實依賴注入促進門面?

你如何處理這種情況?

此外,今天只有一類暴露於外部世界,但未來可能會有兩個或三個,所以這意味着我需要三個外立面?

感謝

+0

這種依賴注入是如何進行的?事實上,你的設計促進了外牆。這是外部代碼訪問故意隱藏類的唯一方式(除了InternalsVisibleTo)。 –

+0

你的意思是你的一個公共類取決於內部類(通過構造函數/屬性注入)? – Matthew

+0

@Matthew是的,這正是我想通過構造器注入(最好) – shankbond

回答

1

做了很多的研究,我寫我的研究結果,因此,它可能是一些幫助,以新人的依賴注入


誤區關於我目前的設計和依賴注入後:

初始方法以及與之相關的問題:

我的業務層有一個組合根,其中 它應該在業務層之外並且靠近應用程序 入口點。在組成方面,我基本上有一個大工廠,稱爲Poor Man's DI by Mark Seemann。在我的應用程序起點上,我創建了這個工廠類的一個實例,然後創建了我的唯一(打算是)可見類到外部世界。這個決定顯然違反Liskov's Principle這說明每個依賴應該是可替換的。我有一個模塊化設計,但我以前的方法是緊密結合的,儘管只有一些代碼清潔和代碼可維護性,但我無法從中獲得更多的好處。

更好的方法是:

A very helplful link given by Facio Ratio

的構成根應該是應用程序的根附近的所有依賴類應該公之於衆我提到最初是一個問題;使他們公開我引入低耦合和跟隨Liskov的替代是好的。

1

可以在公共類更改爲界面和程序的其他部分將只知道大概的接口。這裏有一些示例代碼來說明這一點:

public interface IFacade 
{ 
    void DoSomething(); 
} 

internal class FacadeImpl : IFacade 
{ 
    public FacadeImpl(Alfa alfa, Bravo bravo) 
    { 
    } 

    public void DoSomething() 
    { 
    } 
} 

internal class Alfa 
{ 

} 

internal class Bravo 
{ 

} 
+0

阿爾法,布拉沃很有趣:) – shankbond

+0

SO你說我確實需要一個門面? – shankbond

+1

我想說的是公開接口而不是類是好的做法,它可以讓你輕鬆地改變它的內部邏輯並隱藏來自外部世界的實現細節。 –

1

正確,您的組合根目錄中的所有注入依賴項必須可見。這聽起來像你問這個問題:Ioc/DI - Why do I have to reference all layers/assemblies in entry application?

引述馬克·西曼說一部分答案:

你不必硬引用添加到所有需要的庫。相反,您可以使用基於約定的程序集掃描(首選)或XML配置的形式使用後期綁定。

而且這一點,從史蒂芬:

如果你是非常嚴格的使用組件保護您的建築界,你可以簡單的構圖根移動到一個單獨的程序。

但是,你應該問自己爲什麼這樣做值得付出。如果僅僅是爲了強化建築界限,那麼就沒有紀律的替代品。我的經驗是,遵循SOLID原則時,該規則也更易於維護,因爲依賴注入是「粘合劑」。

0

我可以看到三個解決方案,沒有真正的好處。您可能想要將它們合併在一起。但是...

首先,在構造函數中放入一些簡單的參數(數字,或許),讓調用者說出他想做什麼,並且新的公共類實例可以用來獲取內部類對象-注入)。 (您可以使用特殊的公共類/接口,這些接口僅用於在此傳遞信息。)這會造成一個尷尬和有限的接口,但對於封裝非常有用。如果調用者更喜歡添加一些快速參數來構建複雜的可注入對象,那麼這可能會奏效。 (當一個方法需要五個你從未聽說過的類的對象時,當你需要或者甚至想要的唯一選項是「只讀」和「可編輯」時,這總是一種拖拽。)

其次,你可以製作你的內部類是公開的。現在來電者擁有巨大的權力,可以做任何事情。如果調用代碼真的是系統的核心,那麼這很好,但如果你不太相信代碼或者調用者真的不想被所有挑剔的細節困擾,那就很糟糕。

第三,你可能會發現你可以從調用代碼中拉出一些類到你的程序集中。如果你真的很幸運,那麼打電話的班級可能會在內部工作得更好(希望不會把這個問題重新引入一級)。

迴應評論:

據我瞭解,你有一個服務調用一個公共類的方法在業務層。要進行調用,它需要業務層中其他類的對象。這些其他類是並且應該是內部的。例如,您想調用一個名爲GetAverage的方法,並將其傳遞給(內部)類RoundingPolicy的一個實例,以便知道如何進行四捨五入。我的第一個回答是,你應該採用一個整數值而不是一個類:一個常量值,例如ROUND_UP,ROUND_DOWN,NEAREST_INTEGER等。然後,GetAverage將使用此數字在業務層內生成適當的RoundingPolicy實例,從而使RoundingPolicy保持內部。

我的第一個答案是我建議的。然而,它給服務提供了一個相當原始的界面,所以我的第二個答案提出了替代方案。

第二個答案實際上是你試圖避免的。我的想法是,如果服務所需的所有內部類都是,可能沒有辦法解決問題。在我上面的示例中,如果服務在傳遞它之前使用30行代碼構建正確的RoundingPolicy實例,那麼您將不會使用幾個整數參數來解決問題。你需要給整體設計很多想法。

第三個答案是一個孤獨的希望,但您可能會發現調用代碼正在做的工作,可以很容易地在業務層內完成。這實際上類似於我的第一個答案。然而,在這裏,界面可能更優雅。我的第一個答案限制了服務的功能。這個答案表明該服務不想做太多事情;它總是使用一個相同的RoundingPolicy實例,因此您甚至不需要傳遞參數。

我可能沒有完全理解你的問題,但我希望在這裏有一個想法,你可以使用。

還有更多:第四答:

我認爲這是一個有點我的第一個答案的一部分,但我已經想通了,認爲我應該明確說明它。

我不認爲你要調用的類需要一個接口,但是你可以爲所有你不想公開的接口提供接口。例如IRoundingPolicy。您將需要一些方法來獲得這些接口的實際實例,因爲new IRoundingPolicy()不起作用。現在該服務暴露於您試圖隱藏的所有類的複雜性(向下),但他們無法在類內看到(正面)。您可以精確地控制服務的功能 - 原始類仍然是封裝的。這也許使我的第二個答案成爲可行的版本。這可能是有用的一個或兩個地方的服務需要更多精心選擇比我的第一個答案允許。

+0

對於第二種方法,我認爲只公開與外界相關的類是一個好主意。但是在你的方法中,我需要將所有的依賴關係及其依賴關係暴露給外部世界,這些都是無關緊要的。 – shankbond

+0

對於第三種方法,調用類不過是一種服務,正在做實際工作的主要類都封裝在業務層組件中。在該服務的啓動方法上,我只創建該公共類的一個實例,並在獨立線程上調用其唯一的公開類方法。 – shankbond

+0

@RalphChaping對於你的第一種方法,我不明白你在說什麼? – shankbond