简体   繁体   English

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

[英]Service Locator easier to use than dependency Injection?

The application I am working on is relying on Autofac as DI container and one of the reasons that made me decide to use it, among others, was the delegate factory feature (see here ) 我正在处理的应用程序依赖于Autofac作为DI容器,其中一个原因让我决定使用它,其中包括委托工厂功能(见这里

This works fine for all cases where I need to recreate the same elements several times as is the case of some reports and related screens. 这适用于我需要多次重建相同元素的所有情况,如某些报告和相关屏幕的情况。 Some reports (even those of the same type) are executed concurrently but they change only by their user-defined parameters so it makes sense (I think) to inject factories in order to create instances, passing the free parameters and leave the rest to the application. 一些报告(甚至那些相同类型的报告)是同时执行的,但它们仅通过用户定义的参数进行更改,因此注入工厂以创建实例,传递免费参数并将其余参数留给应用。

The problem comes with the fact that each report is made of a variable number of sub reports (tasks) and each task implements an ITask interface. 问题在于每个报告由可变数量的子报告(任务)组成,每个任务都实现ITask接口。 Each report may have up to 50 different tasks to use and each task encapsulates a precise business operation. 每个报告最多可以使用50个不同的任务,每个任务都包含一个精确的业务操作。 One option I have is to inject delegate factories for and create them when needed. 我有一个选择是注入委托工厂并在需要时创建它们。

These tasks have to be dynamically generated by factories and something like: 这些任务必须由工厂动态生成,例如:

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

requires a lot of manual wiring (delegates, constructor, backing fields etc) while something like 需要大量的手动布线(代表,构造函数,支持领域等)

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

would be incredibly less work especially if the _taskFactory wraps the container as shown in this other post , but also it would basically mean I am using a service locator to create my tasks. 如果_taskFactory包装容器正如一篇文章中所示, 将是非常少的工作,但它也基本上意味着我使用服务定位器来创建我的任务。

What other options do I have that may be suitable to solve this? 我还有哪些其他选择可能适合解决这个问题?

(NOTE: there is a good chance I am completely off track and that I have to read a lot more about DI, in which case any contribution would be even more important) (注意:我很有可能完全偏离轨道,我必须阅读更多有关DI的信息,在这种情况下,任何贡献都会更加重要)

Since the factories indicated in the question don't take any arguments, using a factory smells of a Leaky Abstraction . 由于问题中指出的工厂没有采取任何论据,使用工厂气味的漏水抽象 As Nicholas Blumhardt points out in his answer, a better approach might be to simply inject each task into the consumer. 正如Nicholas Blumhardt在他的回答中指出的那样,更好的方法可能是简单地将每项任务注入消费者手中。

In this case, since all the tasks implement the same interface, instead of injecting up to 50 different ITask instances, you can compose them: 在这种情况下,由于所有任务都实现了相同的接口,而不是注入多达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
        }
    }
}

Alternatively, you can compose the sequence of ITasks into a Composite , which is actually my preferred solution: 或者,您可以将ITasks序列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
}

This would simplify the consumer and turn the fact that there are more than one task to be performed into an implementation detail: 这将简化消费者并将实现细节中执行多个任务的事实转变为:

public class MyConsumer
{
    private readonly ITask task;

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

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

One approach worth investigating is to break the problem into'units of work' that use a set of related tasks: 值得研究的一种方法是将问题分解为使用一组相关任务的“工作单元”:

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

Then, your use of factories would come down towards someWorkFactory().DoSomething() , possibly for a few different kinds of 'something'. 然后,你对工厂的使用会降向someWorkFactory().DoSomething() ,可能会出现几种不同的'某事'。

A class having a large number of dependencies, on factories or anything else, usually points to there being smaller, more focused classes waiting to be discovered to break up the work. 在工厂或其他任何事物上具有大量依赖关系的类通常指向等待被发现以打破工作的更小,更集中的类。

Hope this helps. 希望这可以帮助。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 服务定位器和依赖注入 - Service locator and dependency injection 使用哪种模式进行记录? 依赖注入或服务定位器? - Which pattern to use for logging? Dependency Injection or Service Locator? 从服务定位器到依赖注入 - Moving from Service Locator to Dependency Injection 没有服务定位器的多实例的依赖注入 - Dependency injection for multiple instance without service locator 使用依赖注入(Autofac)并避免服务定位器模式 - Using Dependency Injection (Autofac) and avoiding Service Locator pattern 创建易失性接口实例-依赖注入与服务定位器 - Creating volatile interfaces instances - dependency injection vs service locator 如何将此服务定位器模式转换为真正的依赖注入模式? - How to turn this Service Locator pattern into true Dependency Injection pattern? MVVM +服务+实体框架和依赖注入与服务定位器 - MVVM + Services + Entity Framework and Dependency Injection vs Service Locator 是否可以在应用程序启动时不使用服务定位器来实现依赖注入? - Is it possible to implement dependency injection without using service locator at the start of an application? Seemann的依赖注入,“三个呼叫模式”与服务定位器Anit-Pattern - Seemann's Dependency Injection, “Three Calls Pattern” vs Service Locator Anit-Pattern
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM