2012-01-16 52 views
1

有這個軟件,X,它有這個非常複雜的API,我必須寫一個門面。我寫了一個類庫XClientLibrary,並使用DI和IoC容器(Unity)製作了它。這是可能的,因爲我的庫導出服務(接口),所以用戶不知道使用構造函數DI的具體類。他們也不知道IoC容器。DI:在使用子容器時註冊 - 解析 - 發佈

「根服務」是一個IXClient實例,應該運行應該創建一次並使用它。 (這是一個桌面應用程序btw)。 X客戶端允許用戶連接到X主機,如果他們知道URL。 X主機允許用戶訪問主機的服務及其服務等(非常複雜的對象圖)。這是示例用戶代碼:

// 1. app startup 
XClientProvider provider = new XClientProvider(); // call only once per app 
IXClient xClient = provider.GetClient(); // always returns the same instance  
xClient.Startup(); 

// 2. app normal usage 
IXHost host = xClient.ConnectToHost(new Uri("http://localhost")); // return new instance each time 
IXService1 service = host.GetThis(); 
IXService2 otherService = service.DoThat(); 
... 
host.Dispose(); 

// get another host, consume it, dispose it, etc 
... 

// 3. app shutdown  
xClient.Shutdown(); 
provider.Dispose(); 

我試圖跟蹤Mark塞曼的建議,以實現這一點,但我不知道它們是否適用於一個類庫了。客戶端提供程序是組合根,這是唯一使用IoC容器的位置。該組合物根如下RRR pattern

  • 容器上new XClientProvider()創建和配置
  • 主叫GetClient()
  • 容器被設置在provider.Dispose()

事情當容器可解決IXClient變得複雜時該容器被要求解決IXHost。它的實現:

internal class XHost : IXHost  
    public XHost(Uri uri, IXService1 service1) 

客戶端應該創造XHost實例,所以它的實現需要知道如何創建IXService1

internal class XClient : IXClient 
    public XClient(Func<IXService1> xService1DelegateFactory) 

調用委託工廠達到它創建了一個IXService1容器。此外,讓我們說,在這個圖中有一類XComponent7要求其用於創建主機的確切IXService1實例:

internal class XComponent7 : IXService7 
    public XComponent7(Func<IXService1> service1DelegateFactory) 

我不得不使用Func處理循環依賴。容器應該配置成一旦解決了IXService1,每當要求解決IXService1時,它將提供相同的實例。


現在變得非常複雜。我想限制這種行爲「per host resolve」,這意味着一旦創建了一個主機,容器應該創建一個IXService1並緩存它並將其提供給任何需要它的組件,只要該組件是主機對象圖的一部分。當處理主機時,我還需要一種方法來處置所有組件。

我在想我可以使用子容器來做到這一點。當用戶撥打ConnectToHost時,我可以創建一個,請求它解析主機並將其置於主機處置。主容器仍然存在,直到他們在供應商處撥打Dispose纔會被處置。

問題是,我認爲它打破了RRR模式。所以我想知道如何使用小孩容器時RRR的作品...也許IXHost是另一個「根」,可以由組合根直接解決?或者也許有一個非常聰明的Unity終身經理可以做我需要的東西?

+0

在我甚至試圖弄清楚你的對象圖和你想要做什麼之前:你能解釋一下你的意思是客戶端,主機,服務和組件嗎?對我來說,客戶似乎可以訪問你所謂的主機(比如某種類型的註冊表)。這些主機提供您打電話的服務實際上做些什麼? – 2012-01-16 21:38:08

+0

@Sebastian服務和組件定義在這裏(http://stw.castleproject.org/Windsor.Services-and-Components.ashx)。主機是某種DNS主機,客戶端是訪問主機的手段。我的用戶不能'var host = new Host(uri)',所以我必須爲他們提供另一種方式:'var host = client.ConnectToHost(uri)'。我不確定「客戶」是否是一個好名字... – Suiden 2012-01-16 21:55:30

回答

1

@Suiden所以我的理解是:你的客戶是讓你查找主機(如註冊表)的東西。主機提供由組件實現的服務。每個應用程序只有一個查詢/客戶端實例。你的組件不僅實現服務,而且可能需要其他服務來完成他們的工作。您想要精確地解析該對象圖的所有部分,並在處置客戶端時將其全部丟棄。

一對夫婦的想法:依賴(或服務)之間

循環引用的東西,你應該儘量避免。如果這些服務需要彼此表明它們應該是一項服務。這就是高內聚性,低耦合性。

Unity本身沒有清理乾淨。這意味着即使您處置不會處理由該容器創建的對象的容器。清理功能在wish list for Unity vNext

如果您想解析某個服務的實例並在客戶端/主機內緩存該實例,無論您應該看看懶惰。需要Func來創建T的一個實例,並在第一次請求該值時評估該實例是Func。因此,您可以將Func注入您的課程或teach Unity to inject Lazy instances directly

子容器是一個功能,我發現不到有用的。您可以範圍註冊信息和對象生命週期。但要使用這些範圍,您必須引用適當的子容器。這意味着你正在放棄依賴注入來支持ServiceLocator anti-pattern

+0

- 這是真的每個應用程序都有我的客戶端的一個實例。這是我在應用程序關閉時需要處理的一個圖形。然而,客戶端可以創建主機,所以這些是其他N個圖,我需要在應用程序處置主機時處理這些圖。 - 我會更多地考慮循環依賴的東西。感謝提示 - 如果Unity留下混亂,那麼我會替換它 - 我開始在這個項目中使用Lazy,雖然我買不起4.0,所以我有我自己的實現 - ServiceLocator ...是的,一直那裏,做到了。然後,我在幾個月前看到Mark的帖子,所以現在我試着避免它 – Suiden 2012-01-17 17:23:19

+0

@Suiden如果我的答案有幫助,如果你可以標記它,那將是非常好的。 – 2012-01-18 10:03:32

+0

當然,+1。感謝您提出這些建議! – Suiden 2012-01-22 12:08:07