Внедрение зависимости

В объектно-ориентированном программировании, шаблон дизайна , который регулирует зависимости с объектом на время выполнения , называются , как инъекции зависимостей ( DI , английская зависимость «зависимости» и инъекция «инъекция», немецкая  зависимость инъекция или введение зависимостей ) Другая задача, это Зависимость хранится в центральном месте - она ​​не создается самим инициализированным объектом.

Значение слова

Термин «внедрение зависимостей» был введен в 2004 году разработчиком программного обеспечения Мартином Фаулером, чтобы прояснить тогдашний термин « инверсия управления» : « Инверсия управления - это слишком общий термин, и поэтому людей он сбивает с толку. В результате, после многочисленных дискуссий с различными сторонниками [Inversion of Control], мы остановились на названии Dependency Injection. »( Мартин Фаулер : martinfowler.com)

фоны

С помощью внедрения зависимостей можно - в соответствии с принципом единой ответственности  - передать ответственность за построение сети зависимостей между объектами программы от отдельных классов к центральному компоненту .

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

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

Преимущества и недостатки

преимущества

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

недостаток

  • Создаются клиенты, детали конфигурации которых должны быть предоставлены кодом проекта. Это может быть неприятно, когда доступны очевидные настройки по умолчанию.
  • Чтение кода может быть затруднено, поскольку оно отделяет поведение от построения. Это означает, что разработчикам необходимо обращаться к другим файлам, чтобы отслеживать производительность системы.
  • Фреймворки внедрения зависимостей реализуются с помощью отражения или динамического программирования . Это может помешать использованию автоматизации IDE , например Б. Поиск ссылок, просмотр иерархии вызовов и безопасный рефакторинг . Использование отражения также может повлиять на производительность программы.
  • Как правило, требуется больше предварительных работ по разработке, потому что вы не можете предсказать, когда и где это будет необходимо, а скорее спросите, будет ли он введен, а затем убедитесь, что он был введен.
  • Требуются усилия, чтобы выйти из классов и установить связи между классами, которые не всегда могут быть желательными или простыми в обслуживании.
  • Может усиливаться зависимость от инфраструктуры внедрения зависимостей.

состав

На диаграмме классов UML класс клиента, для которого требуются объекты ServiceA и ServiceB , не создает экземпляры классов ServiceA1 и ServiceB1 напрямую. Вместо этого класс Injector создает объекты и внедряет их в клиент , делая клиента независимым от того, как создаются объекты.

В UML - диаграмма последовательности показывает , среда выполнения взаимодействия: The Инжектор - объект создает ServiceA1 и ServiceB1 объектов . Инжектор затем создает на клиентский объект и впрыскивает ServiceA1 и ServiceB1 объектов.

выполнение

Мартин Фаулер описывает три различных способа установки требуемых ссылок, которые он ассоциирует с термином «Внедрение зависимостей»: «Внедрение конструктора» , « Внедрение интерфейса» и «Внедрение установщика» (раздел « Формы внедрения зависимостей» ). Все описанные им процедуры используют вызовы методов, в которых устанавливаемые зависимости являются не возвращаемыми значениями, а параметрами .

Внедрение конструктора

Зависимости от других классов доступны через конструкторы.

class Abhängiges {
  private Abhängigkeit abhängigkeit;

  //Konstruktor
  public Abhängiges(final Abhängigkeit abhängigkeit) {
    this.abhängigkeit = abhängigkeit;
  }
}

class Injizierer {
  void methode() {
    final Abhängigkeit abhängigkeit = ... ;
    final Abhängiges abhängiges = new Abhängiges(abhängigkeit);
  }
}

Внедрение интерфейса

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

interface IInjizierbar {
  void injiziere(final Abhängigkeit abhängigkeit);
}

class Abhängiges implements IInjizierbar {
  private final Abhängigkeit abhängigkeit;

  public void injiziere(final Abhängigkeit abhängigkeit) {
    this.abhängigkeit = abhängigkeit;
  }
}

class Injizierer {
  void methode() {
    final Abhängigkeit abhängigkeit = ... ;
    final IInjizierbar injizierbares = ... ;
    injizierbares.injiziere(abhängigkeit);
  }
}

Инъекция сеттера

Зависимый класс предоставляет методы, которые используются для предоставления зависимостей.

class Abhängiges {
  private Abhängigkeit abhängigkeit;

  public void setAbhängigkeit(final Abhängigkeit abhängigkeit) {
    this.abhängigkeit = abhängigkeit;
  }
}

class Injizierer {
  void methode() {
    final Abhängiges abhängiges = ... ;
    final Abhängigkeit abhängigkeit = ... ;
    abhängiges.setAbhängigkeit(abhängigkeit);
  }
}

Дальнейшие варианты реализации

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

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

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

Этого недостатка можно избежать, реализовав внедрение зависимостей, аналогичное шаблону проектирования Абстрактная фабрика, без использования фреймворка как части самой программы. Этот тип реализации называется «Самостоятельное внедрение зависимостей» или для краткости «DIY-DI».

Индивидуальные доказательства

  1. Внедрение зависимостей в ASP.NET Core , Microsoft Docs
  2. ^ A b Мартин Фаулер: инверсия управляющих контейнеров и шаблон внедрения зависимостей. 23 января 2004 г. (английский) Проверено 16 мая 2013 г.
  3. Как работает внедрение зависимостей (DI) при разработке приложений Java Spring. DZone
  4. Бен Ю: Типы внедрения зависимостей. ( Memento из в оригинале с 18 августа 2013 года в Internet Archive ) Info: архив ссылка была вставлена автоматически и еще не была проверена. Пожалуйста, проверьте исходную и архивную ссылку в соответствии с инструкциями, а затем удалите это уведомление. (На английском языке), доступ осуществлен 16 мая 2013 г. @ 1@ 2Шаблон: Webachiv / IABot / yan.codehaus.org
  5. Чад Парри: DIY-DI (PDF) 9 марта 2010 г. По состоянию на 29 июня 2014 г.