2011-11-10 93 views
6

我工作中的應用是依靠Autofac作爲DI容器的,使我決定使用它,以及其他的原因之一,是代表工廠功能(見here服務定位器比依賴注入更容易使用?

也能正常工作的所有情況在那裏我需要多次重新創建相同的元素,就像一些報告和相關屏幕一樣。一些報告(即使是相同類型的報告)是同時執行的,但它們只是通過用戶定義的參數進行更改,所以爲了創建實例注入工廠是有意義的(我認爲),傳遞免費參數並將其餘部分留給應用。

問題伴隨着每個報告由可變數量的子報告(任務)組成並且每個任務實現ITask接口。每份報告最多可以有50個不同的任務使用,每個任務都包含精確的業務操作。我有一個選擇是注入委託工廠並在需要時創建它們。

這些任務必須由工廠和喜歡的東西是動態生成的:

var myTaskA = _taskFactoryConcreteTaskA(); 
var myTaskB = _taskFactoryConcreteTaskB(); 
var myTaskC = _taskFactoryConcreteTaskC(); 
... 
var myTaskZZ = = _taskFactoryConcreteTaskZZ(); 

需要大量的手工佈線(代表,構造,支持字段等等),而像

var myTaskA = _taskFactory.Create<ConcreteTaskA>(); 
var myTaskB = _taskFactory.Create<ConcreteTaskB>(); 
var myTaskC = _taskFactory.Create<ConcreteTaskC>(); 
... 
var myTaskZZ = _taskFactory.Create<ConcreteTaskZZ>(); 

會特別是如果_taskFactory包裝了容器,如this other post所示,但它也意味着我正在使用服務定位器來創建我的任務。

我有哪些其他選擇可能適合解決此問題?

(注:有一個很好的機會,我完全偏離軌道,並且我要讀了很多有關DI,在這種情況下,任何的貢獻將更爲重要)

+0

Martin Fowler的寫了這點:http://martinfowler.com/articles/injection.html#UsingAServiceLocator – mwilson

+2

謝謝,這是什麼讓我再想想文章很多:HTTP: //blog.ploeh.dk/2010/02/03/ServiceLocatorIsAnAntiPattern.aspx(並說服我購買這本書,但仍在等待它) – mhttk

回答

3

一種方法值得研究的是打破工作的問題into'units」使用一組相關任務:

public class WorkItem1 : ISomeWork 
{ 
    public WorkItem1(Task1 t1, Task2 t2...) { } 
    public void DoSomething() { ... } 
} 

然後,你的工廠的使用將回落向someWorkFactory().DoSomething(),可能是幾個不同類型的‘東西’。

有大量的相關性,在工廠或其他任何一類,通常指向那裏正在變小,等待更集中的類被發現,打破了工作。

希望這會有所幫助。

+0

+1但是,請參閱我的答案以獲取更多選項。 –

+0

謝謝,這很有趣,因爲它實際上可能適合我。在一個報告類中使用多個任務的事實是讓每個任務都能解決複雜報告的特定部分,從而通過更加清晰的方式降低整體代碼的複雜性。也許可以通過分解報告的子部分,然後讓工廠在需要時進行實例化。 – mhttk

6

由於問題中提到的工廠沒有采取任何論據,所以使用工廠的氣味漏泄抽象。正如Nicholas Blumhardt在他的回答中所指出的,更好的方法可能是將每項任務簡單地注入消費者。

在這種情況下,由於所有的任務,實現相同的接口,而不是注入多達50種不同的ITask情況下,您可以撰寫他們:

public class MyConsumer 
{ 
    private readonly IEnumerable<ITask> tasks; 

    public MyConsumer(IEnumerable<ITask> tasks) 
    { 
     this.tasks = tasks; 
    } 

    public void DoSomething() 
    { 
     foreach (var t in this.tasks) 
     { 
      // Do something with each t 
     } 
    } 
} 

或者,您也可以撰寫的ITasks序列劃分Composite,這實際上是我的首選解決方案:

public CompositeTask : ITask 
{ 
    private readonly IEnumerable<ITask> tasks; 

    public CompositeTask(IEnumerable<ITask> tasks) 
    { 
     this.tasks = tasks; 
    } 

    // Implement ITask by iterating over this.tasks 
} 

這將簡化消費者和轉向的事實,有要執行到執行細節多個任務:

public class MyConsumer 
{ 
    private readonly ITask task; 

    public MyConsumer(ITask task) 
    { 
     this.task = task; 
    } 

    public void DoSomething() 
    { 
     // Do something with this.task 
    } 
} 
+0

謝謝,我考慮過這種情況,但我不確定我是否理解你在這裏提出的建議。如果我創建了一個複合任務,我仍然需要注入一個'IEnumerable ',但是誰將在集合中插入正確的任務?也許我沒有解釋過不同的報告使用不同的任務組,並且在這個例子中你假設注入所有可用的任務?你和Nicholas Blumhardt的例子仍然提供有用的見解,謝謝。 – mhttk

+2

作曲家(作曲家根)決定在哪些任務注入哪裏。儘管*可以*在所有*報告中注入所有ITask實現,但您也可以爲每個報告選擇一個子集。使用DI容器時,這只是正確配置容器的問題。 –

+0

我明白了,這非常有趣。這讓我明白@ NicholasBlumhardt的建議暗示了什麼。謝謝。 (ps我熱切地等待[這本書](http://manning.com/seemann/)被交付,很棒的工作!) – mhttk