Рассмотреть возможность:
public class CtorInjectionExample
{
public CtorInjectionExample(ISomeRepository SomeRepositoryIn, IOtherRepository OtherRepositoryIn)
{
this._someRepository = SomeRepositoryIn;
this._otherRepository = OtherRepositoryIn;
}
public void SomeMethod()
{
//use this._someRepository
}
public void OtherMethod()
{
//use this._otherRepository
}
}
против:
public class MethodInjectionExample
{
public MethodInjectionExample()
{
}
public void SomeMethod(ISomeRepository SomeRepositoryIn)
{
//use SomeRepositoryIn
}
public void OtherMethod(IOtherRepository OtherRepositoryIn)
{
//use OtherRepositoryIn
}
}
Хотя внедрение Ctor затрудняет расширение (любой код, вызывающий ctor, будет нуждаться в обновлении при добавлении новых зависимостей), и внедрение уровня метода, похоже, остается более инкапсулированным из зависимости уровня класса, и я не могу найти никаких других аргументов за / против этих подходов ,
Есть ли определенный подход для инъекций?
(NB. Я искал информацию по этому вопросу и пытался сделать этот вопрос объективным.)
Ответы:
Это зависит, если внедренный объект используется более чем одним методом в классе, и внедрение в него для каждого метода не имеет смысла, вам нужно разрешить зависимости для каждого вызова метода, но если зависимость используется только один метод, добавленный в конструктор, не очень хорош, но так как вы выделяете ресурсы, которые никогда не могут быть использованы.
источник
Хорошо, во-первых, давайте разберемся с «Любой код, вызывающий ctor, будет нуждаться в обновлении при добавлении новых зависимостей»; Для ясности, если вы делаете внедрение зависимостей и у вас есть какой-либо код, вызывающий new () для объекта с зависимостями, вы делаете это неправильно .
Ваш DI-контейнер должен быть в состоянии внедрить все соответствующие зависимости, так что вам не нужно беспокоиться об изменении сигнатуры конструктора, чтобы этот аргумент действительно не сохранялся.
Что касается идеи внедрения метода по сравнению с методом в классе, то есть две основные проблемы, связанные с внедрением метода.
Одна из проблем заключается в том, что методы вашего класса должны совместно использовать зависимости. Это один из способов обеспечить эффективное разделение классов: если вы видите класс с большим количеством зависимостей (вероятно, более 4-5), то этот класс является основным кандидатом. для рефакторинга на два класса.
Следующая проблема заключается в том, что для того, чтобы «внедрить» зависимости для каждого метода, вам необходимо передать их в вызов метода. Это означает, что вам придется разрешить зависимости перед вызовом метода, так что вы, скорее всего, получите такой код:
Теперь предположим, что вы собираетесь вызывать этот метод в 10 местах вашего приложения: у вас будет 10 таких фрагментов. Далее, скажем, вам нужно добавить еще одну зависимость в DoStuff (): вам придется изменить этот фрагмент 10 раз (или обернуть его в методе, и в этом случае вы просто реплицируете поведение DI вручную, что является пустой тратой) времени).
Таким образом, то, что вы в основном сделали, это заставило ваши классы, использующие DI, знать о своем собственном контейнере DI, что является принципиально плохой идеей , поскольку очень быстро приводит к неуклюжей конструкции, которую трудно поддерживать.
Сравните это с инжектором конструктора; При внедрении в конструктор вы не привязаны к конкретному контейнеру DI и никогда не несете прямой ответственности за выполнение зависимостей ваших классов, поэтому обслуживание практически не требует головной боли.
Мне кажется, что вы пытаетесь применить IoC к классу, содержащему кучу несвязанных вспомогательных методов, тогда как вам лучше разделить вспомогательный класс на несколько классов обслуживания в зависимости от использования, а затем использовать помощника для делегирования звонки. Это все еще не очень хороший подход (помощник, классифицируемый с методами, которые делают что-то более сложное, чем просто обработка переданных им аргументов, как правило, просто плохо написанные классы обслуживания), но он по крайней мере сделает ваш дизайн немного чище ,
(NB. Я использовал подход, который вы предлагаете ранее, и это была очень плохая идея, которую я не повторял с тех пор. Оказалось, что я пытался выделить классы, которые действительно не нужно разделять, и в итоге с набором интерфейсов, где каждый вызов метода требовал почти фиксированного выбора других интерфейсов. Это был кошмар для обслуживания.)
источник
"if you're doing dependency injection and you have any code calling new() on an object with dependencies, you're doing it wrong."
Если вы проводите модульное тестирование метода в классе, вы должны создать его экземпляр или используете DI для создания экземпляра тестируемого кода?"any code calling the ctor will need updating"
, что мой рабочий код не вызывает ctors. По этим причинам.Существуют различные виды инверсии управления , и в вашем вопросе предлагается только два (вы также можете использовать фабрику для внедрения зависимости).
Ответ: это зависит от необходимости. Иногда лучше использовать один вид, а другой - другой.
Мне лично нравятся инжекторы конструктора, так как конструктор предназначен для полной инициализации объекта. Позже вызов сеттера делает объект не полностью построенным.
источник
Вы пропустили ту, которая, по крайней мере для меня, является самой гибкой - инъекция свойства. Я использую Castle / Windsor, и все, что мне нужно сделать, это добавить новое свойство auto в свой класс, и я получаю внедренный объект без каких-либо проблем и без нарушения интерфейсов.
источник