2011-11-10 95 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