Сервисный локатор проще в использовании, чем инъекция зависимостей? - PullRequest
6 голосов
/ 11 ноября 2011

Приложение, над которым я работаю, использует Autofac в качестве DI-контейнера, и одной из причин, по которой я решил использовать его, была, среди прочего, функция фабрики делегатов (см. здесь )

Это прекрасно работает для всех случаев, когда мне нужно воссоздать одни и те же элементы несколько раз, как в случае некоторых отчетов и связанных экранов. Некоторые отчеты (даже отчеты одного и того же типа) выполняются одновременно, но они изменяются только по своим пользовательским параметрам, поэтому имеет смысл (я думаю) вводить фабрики для создания экземпляров, передавая свободные параметры и оставляя остальные применение.

Проблема заключается в том, что каждый отчет состоит из переменного количества подотчетов (задач), и каждая задача реализует интерфейс 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 оборачивает контейнер, как показано в этом другом посте , но это также в основном означает, что я использую сервисный локатор для создания своих задач.

Какие еще есть варианты, которые могут подойти для решения этой проблемы?

(ПРИМЕЧАНИЕ: есть большая вероятность, что я совершенно не в курсе, и мне нужно больше читать о DI, и в этом случае любой вклад будет еще более важным)

Ответы [ 2 ]

6 голосов
/ 11 ноября 2011

Поскольку фабрики, указанные в вопросе, не принимают никаких аргументов, используются фабричные запахи Leaky Abstraction . Как указывает в своем ответе Николас Блюмхардт, лучшим подходом может быть простое внедрение каждой задачи потребителю.

В этом случае, поскольку все задачи реализуют один и тот же интерфейс, вместо внедрения до 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
    }
}
3 голосов
/ 11 ноября 2011

Один из подходов, который стоит изучить, состоит в том, чтобы разбить проблему на «единицы труда», которые используют набор связанных задач:

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

Тогда ваше использование фабрик сведется к someWorkFactory().DoSomething(), возможно, для нескольких разных видов "чего-то".

Класс, имеющий большое количество зависимостей, от фабрик или чего-либо еще, обычно указывает на то, что есть более мелкие, более сфокусированные классы, ожидающие, чтобы их обнаружили, чтобы разбить работу.

Надеюсь, это поможет.

...