Когда вы используете внедрение зависимостей?

StackOverflow https://stackoverflow.com/questions/28464

  •  09-06-2019
  •  | 
  •  

Вопрос

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

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

Это было полезно?

Решение

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

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

Другие советы

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

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

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

Использование, которое я счел полезным для инверсии шаблона управления:

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

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

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

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

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

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

Редактировать:Вы упоминаете множество интерфейсов в конструкторе.Я бы посоветовал вместо этого использовать сеттеры / геттеры.Я нахожу, что это значительно упрощает обслуживание в долгосрочной перспективе.

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

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

Но в этом-то все и дело...во всех остальных случаях это просто сделало бы систему излишне сложной

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

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

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

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

Я использую Castle Windsor / Микроядро, у меня нет опыта работы с чем-либо другим, но мне это очень нравится.

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

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

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top