Когда вы используете инъекцию зависимости? - PullRequest
16 голосов
/ 26 августа 2008

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

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

Ответы [ 9 ]

22 голосов
/ 26 августа 2008

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

Что вы действительно делаете, так это переносите эту связь со времени компиляции на среду выполнения, но, тем не менее, если для работы класса A необходим некоторый интерфейс B, экземпляр класса, который реализует интерфейс B, все еще необходимо предоставить.

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

Использование, которое я видел полезным для паттерна «Инверсия контроля»:

  • Плагин архитектуры. Таким образом, сделав правильные точки входа, вы можете определить договор на услугу, которая должна быть предоставлена.
  • Архитектура, похожая на рабочий процесс. Где вы можете подключить несколько компонентов, динамически соединяя выход компонента со входом другого.
  • Клиентское приложение. Допустим, у вас есть различные клиенты, которые оплачивают набор «функций» вашего проекта. Используя внедрение зависимостей, вы можете легко предоставить только основные компоненты и некоторые «добавленные» компоненты, которые предоставляют только те функции, которые заплатил клиент.
  • Перевод. Хотя это обычно не делается для целей перевода, вы можете «внедрить» различные языковые файлы в соответствии с требованиями приложения. Сюда входят пользовательские интерфейсы RTL или LTR по мере необходимости.
9 голосов
/ 26 августа 2008

Подумайте о своем дизайне. DI позволяет вам изменить работу вашего кода через изменения конфигурации. Это также позволяет вам разбивать зависимости между классами, чтобы вы могли легче изолировать и тестировать объекты. Вы должны определить, где это имеет смысл, а где нет. Ответа нет.

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

8 голосов
/ 05 октября 2008

Внедрение зависимостей должно использоваться только для частей приложение, которое нужно динамически менять без перекомпиляции базовый код

DI должен использоваться для изоляции вашего кода от внешних ресурсов (базы данных, веб-сервисы, XML-файлы, архитектура плагинов). Количество времени, которое потребовалось бы для проверки вашей логики в коде, было бы практически недопустимым во многих компаниях, если вы тестируете компоненты, ЗАВИСИМЫЕ от базы данных.

В большинстве приложений база данных не будет изменяться динамически (хотя это может произойти), но, вообще говоря, почти всегда рекомендуется НЕ связывать ваше приложение с конкретным внешним ресурсом. Количество, вовлеченное в изменение ресурсов, должно быть низким (классы доступа к данным редко имеют цикломатическую сложность выше, чем в методах).

2 голосов
/ 26 августа 2008

Я делаю это только тогда, когда это помогает разделить проблемы.

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

Но это все ... во всех остальных случаях это просто усложнит систему

2 голосов
/ 26 августа 2008

Что вы подразумеваете под "просто добавлением свойства в класс?"

Мое эмпирическое правило - сделать юнит класса тестируемым. Если ваш класс опирается на детали реализации другого класса, это необходимо реорганизовать / абстрагировать до такой степени, чтобы классы можно было тестировать изолированно.

РЕДАКТИРОВАТЬ: Вы упомянули множество интерфейсов в конструкторе. Я бы посоветовал вместо этого использовать сеттеры / геттеры. Я считаю, что в долгосрочной перспективе это значительно упрощает обслуживание.

1 голос
/ 26 августа 2008

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

Есть некоторые приложения, которые просто одноразовые, но если есть сомнения, я бы продолжил и создал интерфейсы. После некоторой практики это не большая ноша.

1 голос
/ 26 августа 2008

Даже со всеми фактами и процессами в мире .. каждое решение сводится к призыву к суждению - Забыл, где я прочитал это
Я думаю, что это скорее вызов опыта / времени полета. В основном, если вы видите зависимость как объект-кандидат, который может быть заменен в ближайшем будущем, используйте внедрение зависимости. Если я рассматриваю «classA и его зависимости» как один блок для подстановки, то, вероятно, я не буду использовать DI для deps A.

0 голосов
/ 05 октября 2008

Я использую Castle Windsor / Microkernel, у меня нет опыта ни с чем, но мне это очень нравится.

Что касается того, как вы решаете, что вводить? До сих пор мне помогло следующее практическое правило: если класс настолько прост, что ему не нужны модульные тесты, вы можете свободно создавать его экземпляр в классе, в противном случае вы, вероятно, захотите получить зависимость через конструктор.

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

0 голосов
/ 26 августа 2008

Еще один предмет, с которым я борюсь, это , где мне использовать внедрение зависимостей? Где вы берете свою зависимость от StructureMap? Только в автозагрузке приложения? Означает ли это, что все реализации должны быть переданы от самого верхнего слоя до самого нижнего слоя?

...