服务定位器比依赖注入更容易使用?

mht*_*ttk 6 c# dependency-injection ioc-container autofac

我正在处理的应用程序依赖于Autofac作为DI容器,其中一个原因让我决定使用它,其中包括委托工厂功能(见这里)

这适用于我需要多次重建相同元素的所有情况,如某些报告和相关屏幕的情况.一些报告(甚至那些相同类型的报告)是同时执行的,但它们仅通过用户定义的参数进行更改,因此注入工厂以创建实例,传递免费参数并将其余参数留给应用.

问题在于每个报告由可变数量的子报告(任务)组成,每个任务都实现ITask接口.每个报告最多可以使用50个不同的任务,每个任务都包含一个精确的业务操作.我有一个选择是注入委托工厂并在需要时创建它们.

这些任务必须由工厂动态生成,例如:

var myTaskA = _taskFactoryConcreteTaskA();
var myTaskB = _taskFactoryConcreteTaskB();
var myTaskC = _taskFactoryConcreteTaskC();
...
var myTaskZZ = = _taskFactoryConcreteTaskZZ();
Run Code Online (Sandbox Code Playgroud)

需要大量的手动布线(代表,构造函数,支持领域等)

var myTaskA = _taskFactory.Create<ConcreteTaskA>();
var myTaskB = _taskFactory.Create<ConcreteTaskB>();
var myTaskC = _taskFactory.Create<ConcreteTaskC>();
...
var myTaskZZ = _taskFactory.Create<ConcreteTaskZZ>();
Run Code Online (Sandbox Code Playgroud)

如果_taskFactory包装容器正如一篇文章中所示,将是非常少的工作,但它也基本上意味着我使用服务定位器来创建我的任务.

我还有哪些其他选择可能适合解决这个问题?

(注意:我很有可能完全偏离轨道,我必须阅读更多有关DI的内容,在这种情况下,任何贡献都会更加重要)

Mar*_*ann 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
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

或者,您可以将序列组合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
}
Run Code Online (Sandbox Code Playgroud)

这将简化消费者并将实现细节中执行多个任务的事实转变为:

public class MyConsumer
{
    private readonly ITask task;

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

    public void DoSomething()
    {
        // Do something with this.task
    }
}
Run Code Online (Sandbox Code Playgroud)

  • Composer(Composition Root)决定在哪里注入哪些任务.虽然您可以*在*all*报告中注入所有ITask实现,但您也可以为每个报告选择一个子集.使用DI容器时,这只是正确配置容器的问题. (2认同)

Nic*_*rdt 3

一种值得研究的方法是将问题分解为使用一组相关任务的“工作单元”:

public class WorkItem1 : ISomeWork
{
    public WorkItem1(Task1 t1, Task2 t2...) { }
    public void DoSomething() { ... }
}
Run Code Online (Sandbox Code Playgroud)

然后,你对工厂的使用将归结为someWorkFactory().DoSomething(),可能是为了几种不同类型的“东西”。

一个类对工厂或其他任何东西有大量的依赖关系,通常表明有更小、更集中的类等待被发现来分解工作。

希望这可以帮助。