Вопрос-ответ

How to avoid Dependency Injection constructor madness?

Как избежать безумия конструктора внедрения зависимостей?

Я обнаружил, что мои конструкторы начинают выглядеть следующим образом:

public MyClass(Container con, SomeClass1 obj1, SomeClass2, obj2.... )

с постоянно увеличивающимся списком параметров. Поскольку "Контейнер" - это мой контейнер для внедрения зависимостей, почему я не могу просто сделать это:

public MyClass(Container con)

для каждого класса? Каковы недостатки? Если я делаю это, создается ощущение, что я использую прославленную статику. Пожалуйста, поделитесь своими мыслями о IoC и безумии внедрения зависимостей.

Переведено автоматически
Ответ 1

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

Одно из замечательных преимуществ внедрения конструктора заключается в том, что оно делает нарушения принципа единой ответственности совершенно очевидными.

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

Ответ 2

Я не думаю, что конструкторы ваших классов должны ссылаться на период вашего контейнера IOC. Это представляет собой ненужную зависимость между вашим классом и контейнером (тип зависимости, которого IOC пытается избежать!).

Ответ 3

Сложность передачи параметров не является проблемой. Проблема в том, что ваш класс делает слишком много, и его следует еще больше разбивать.

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

Ответ 4

Проблема :

1) Конструктор с постоянно увеличивающимся списком параметров.

2) Если класс наследуется (например: RepositoryBase), то изменение сигнатуры конструктора вызывает изменения в производных классах.

Решение 1

Передать IoC Container конструктору

Почему


  • Список параметров больше не увеличивается

  • Сигнатура конструктора становится простой

Почему бы и нет


  • Ваш класс тесно связан с контейнером IoC. (Это вызывает проблемы, когда 1. вы хотите использовать этот класс в других проектах, где вы используете другой контейнер IoC. 2. вы решили сменить контейнер IoC)

  • Делает ваш класс менее описательным. (Вы не можете действительно посмотреть на конструктор класса и сказать, что ему нужно для функционирования.)

  • Класс потенциально может получить доступ ко всем сервисам.

Решение 2

Создайте класс, который группирует все службы, и передайте его конструктору

 public abstract class EFRepositoryBase 
{
public class Dependency
{
public DbContext DbContext { get; }
public IAuditFactory AuditFactory { get; }

public Dependency(
DbContext dbContext,
IAuditFactory auditFactory
)

{
DbContext = dbContext;
AuditFactory = auditFactory;
}
}

protected readonly DbContext DbContext;
protected readonly IJobariaAuditFactory auditFactory;

protected EFRepositoryBase(Dependency dependency)
{
DbContext = dependency.DbContext;
auditFactory= dependency.JobariaAuditFactory;
}
}

Производный класс

  public class ApplicationEfRepository : EFRepositoryBase      
{
public new class Dependency : EFRepositoryBase.Dependency
{
public IConcreteDependency ConcreteDependency { get; }

public Dependency(
DbContext dbContext,
IAuditFactory auditFactory,
IConcreteDependency concreteDependency
)

{
DbContext = dbContext;
AuditFactory = auditFactory;
ConcreteDependency = concreteDependency;
}
}

IConcreteDependency _concreteDependency;

public ApplicationEfRepository(
Dependency dependency
)
: base(dependency)

{
_concreteDependency = dependency.ConcreteDependency;
}
}

Почему


  • Добавление новой зависимости к классу не влияет на производные классы

  • Класс не зависит от контейнера IoC

  • Класс является описательным (в аспекте его зависимостей). По соглашению, если вы хотите знать, от какого класса A зависит, эта информация накапливается в A.Dependency

  • Подпись конструктора становится простой

Почему бы и нет


  • необходимо создать дополнительный класс

  • регистрация служб становится сложной (Вам нужно регистрировать каждую X.Dependency отдельно)

  • Концептуально то же самое, что передача IoC Container

  • ..

Решение 2 - это всего лишь сырое, хотя, если есть веские аргументы против него, то был бы признателен за описательный комментарий

c# java