Что такое внедрение зависимостей?

Уже было опубликовано несколько вопросов со специальными вопросами о внедрении зависимости , например, когда его использовать и какие существуют рамки для него. Тем не менее,

Что такое внедрение зависимостей и когда / почему его следует или не следует использовать?

2945
задан 16.05.2020, 23:46

3 ответа

Внедрение зависимости передает зависимость другому объекты или платформа (инжектор зависимости).

Внедрение зависимости делает тестирование легче. Инжекция может быть сделана до [1 124] конструктор .

SomeClass() имеет его конструктора как следующее:

public SomeClass() {
    myObject = Factory.getObject();
}

проблема : Если myObject включает сложные задачи, такие как доступ к диску или доступ к сети, это твердо , чтобы сделать модульный тест на SomeClass(). Программисты должны дразнить myObject, и мог бы прерывание вызов фабрики.

Альтернативное решение :

  • Передача myObject в как аргумент конструктору
public SomeClass (MyClass myObject) {
    this.myObject = myObject;
}

myObject может быть передана непосредственно, который делает тестирование легче.

  • Одна общая альтернатива определяет пустой конструктор . Внедрение зависимости может быть сделано через методы set. (h/t @MikeVella).
  • Martin Fowler документы третья альтернатива (h/t @MarcDix), где классы явно реализуют интерфейс для введенного желания программистов зависимостей.

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

В 2013, когда я записал этот ответ, это было главной темой на Google Testing Blog . Это остается самым большим преимуществом для меня, поскольку программистам не всегда нужна дополнительная гибкость при их разработке во время выполнения (например, для сервисного локатора или подобных шаблонов). Программисты часто должны изолировать классы во время тестирования.

1857
ответ дан 16.05.2020, 23:49
  • 1
    Подтверждение того Ben Hoffstein' s referenceto Martin Fowler' s статья необходимо как указание на ' must-read' на предмете, I' m принимающий wds' ответьте, потому что это на самом деле отвечает на вопрос здесь на ТАК. – AR. 16.05.2020, 23:50
  • 2
    +1 для объяснения и мотивации: создание создания объектов, от которых класс зависит кто-то else' s проблема . Другой способ сказать это состоит в том, что DI делает классы более связными (у них есть меньше обязанностей). – Fuhrmanator 16.05.2020, 23:50
  • 3
    Вы говорите, что зависимость передается " в к constructor" но насколько я понимаю этот isn' t строго верный. It' s все еще внедрение зависимости, если зависимость установлена как свойство после того, как объект инстанцировали, корректен? – Mike Vella 16.05.2020, 23:50
  • 4
    @MikeVella Да, который корректен. Это не имеет никакого реального значения в большинстве случаев, хотя свойства обычно немного более гибки. Я отредактирую текст немного для указания на это. – wds 16.05.2020, 23:50

Лучшее определение, которое я нашел до сих пор, один James Shore :

"Внедрение зависимости" является термином за 25 долларов для понятия за 5 центов. [...] Внедрение зависимости означает давать объекту свои переменные экземпляра. [...].

существует статья Martin Fowler , который может оказаться полезным, также.

Внедрение зависимости в основном обеспечивает объекты, в которых объект нуждается (его зависимости) вместо того, чтобы иметь его создают их сам. Это - очень полезная техника для тестирования, так как это позволяет зависимостям дразниться или гаситься.

Зависимости могут быть введены в объекты многими средствами (такими как инжекция конструктора или инжекция метода set). Можно даже использовать специализированные платформы внедрения зависимости (например, Spring), чтобы сделать это, но они, конечно, не требуются. Вам не нужны те платформы, чтобы иметь внедрение зависимости. Инстанцирование и передача объектов (зависимости) явно являются столь же хорошей инжекцией как инжекция платформой.

2268
ответ дан 16.05.2020, 23:58

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

, Например, рассмотрите эти классы:

public class PersonService {
  public void addManager( Person employee, Person newManager ) { ... }
  public void removeManager( Person employee, Person oldManager ) { ... }
  public Group getGroupByManager( Person manager ) { ... }
}

public class GroupMembershipService() {
  public void addPersonToGroup( Person person, Group group ) { ... }
  public void removePersonFromGroup( Person person, Group group ) { ... }
} 

В этом примере, для реализации PersonService::addManager и PersonService::removeManager был бы нужен экземпляр GroupMembershipService, чтобы сделать его работу. Без Внедрения зависимости традиционный способ сделать это состоял бы в том, чтобы инстанцировать нового GroupMembershipService в конструкторе PersonService лет и использовать тот атрибут экземпляра в обеих функциях. Однако, если у конструктора GroupMembershipService лет есть несколько вещей, это требует, или хуже все же, существует некоторая инициализация "методы set", которые нужно назвать на эти GroupMembershipService, код растет скорее быстро, и PersonService теперь зависит не только от GroupMembershipService, но также и все остальное, что GroupMembershipService зависит от. Кроме того, связь с [1 111] является hardcoded в PersonService, что означает, что Вы не можете "макет" GroupMembershipService для тестирования, или использовать стратегическую модель в различных частях Вашего приложения.

С Внедрением зависимости, вместо того, чтобы инстанцировать GroupMembershipService в Вашем PersonService, Вы или передали бы его в PersonService конструктор или иначе добавили бы Свойство (метод считывания и метод set) для установки локального экземпляра его. Это означает, что Ваш PersonService больше не должен волноваться о том, как создать GroupMembershipService, это просто принимает тех, это дано и работает с ними. Это также означает, что что-либо, что является подклассом [1 119], или реализует эти GroupMembershipService, интерфейс может быть "введен" в эти PersonService, и эти PersonService не должен знать об изменении.

254
ответ дан 17.05.2020, 00:00
  • 1
    @cjrh: I' m любопытный: почему был бы Вы писать " Большой answer" но не голосуют за ответ? Никакое давление... – Ned Batchelder 16.10.2019, 17:14