Мне не нравится внедрение зависимостей на основе конструктора.
Я считаю, что это увеличивает сложность кода и снижает удобство сопровождения, и я хотел бы знать, есть ли какие-либо жизнеспособные альтернативы.
Я не говорю о концепции отделения реализации от интерфейса, а также о способе динамического (рекурсивного) разрешения набора объектов из интерфейса.Я полностью поддерживаю это.Однако традиционный способ, основанный на использовании конструктора, кажется, имеет несколько проблем.
1) Все тесты зависят от конструкторов.
После широкого использования DI в проекте MVC 3 C # надв прошлом году наш код был полон таких вещей:
public interface IMyClass {
...
}
public class MyClass : IMyClass {
public MyClass(ILogService log, IDataService data, IBlahService blah) {
_log = log;
_blah = blah;
_data = data;
}
...
}
Проблема: если мне нужна другая служба в моей реализации, я должен изменить конструктор;и это означает, что все модульные тесты для этого перерыва в классе.
Даже тесты, которые не имеют ничего общего с новой функциональностью, требуют как минимум рефакторинга для добавления дополнительных параметров и введения макета для этого аргумента.
Это кажется небольшой проблемой и автоматизированными инструментами, такими как resharper help, но, безусловно, раздражает, когда простое изменение, подобное этому, приводит к сбою более 100 тестов.Практически говоря, я видел, как люди делали глупые вещи, чтобы не менять конструктор, а не кусать пулю и исправлять все тесты, когда это происходит.
2) Экземпляры службы обходятся без необходимости, что увеличивает сложность кода.
public class MyWorker {
public MyWorker(int x, IMyClass service, ILogService logs) {
...
}
}
Создание экземпляра этого класса, если это возможно, только если я нахожусь в контексте, где указанные службы доступны и были автоматически разрешены (например, контроллер) или, к несчастью, путем передачи экземпляра службы по нескольким цепочкамвспомогательных классов.
Я вижу такой код все время :
public class BlahHelper {
// Keep so we can create objects later
var _service = null;
public BlahHelper(IMyClass service) {
_service = service;
}
public void DoSomething() {
var worker = new SpecialPurposeWorker("flag", 100, service);
var status = worker.DoSomethingElse();
...
}
}
В случае, если пример не ясен, я говорю о передаче разрешенных экземпляров интерфейса DIвниз по нескольким слоям с без причины , кроме как на нижнем уровне, которые они необходимы для внедрения во что-либо.
Если класс не зависит от службы, он должен зависеть отэтот сервис.Идея о том, что существует «временная» зависимость, когда класс не использует сервис, а просто передает его, является, на мой взгляд, бессмысленной.
Однако я не знаю лучшего решения.
Есть ли что-нибудь, что дает преимущества DI без этих проблем?
Я уже думал об использовании DIрамки внутри конструкторов, так как это решает пару проблем:
public MyClass() {
_log = Register.Get().Resolve<ILogService>();
_blah = Register.Get().Resolve<IBlahService>();
_data = Register.Get().Resolve<IDataService>();
}
Есть ли какие-либо недостатки в этом?
Это означает, что модульные тесты должны иметь «предварительные знания» о классе, чтобы связывать макеты для правильных типов во время теста инициализации, но я не вижу никаких других недостатков.
NB.Мои примеры на c #, но я сталкивался с такими же проблемами и на других языках, и особенно языки с менее развитой инструментальной поддержкой - это основные головные боли.