design-patterns пример dependency - Что такое инъекция зависимости?





15 Answers

Лучшее определение, которое я нашел до сих пор, - это Джеймс Шор :

«Инъекция зависимостей» - это 25-долларовый термин для концепции 5 центов. [...] Инъекция зависимости означает предоставление объекту своих переменных экземпляра. [...].

Есть статья Мартина Фаулера, которая может оказаться полезной.

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

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

injection зачем нужен

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

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




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

Например, рассмотрим эти положения:

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 понадобится экземпляр PersonService::removeManager для выполнения его работы. Без Injection Dependency традиционным способом выполнения этого было бы создать экземпляр нового GroupMembershipService в конструкторе PersonService и использовать атрибут экземпляра в обеих функциях. Однако, если конструктор GroupMembershipService имеет несколько вещей, которые он требует, или, что еще хуже, есть некоторые инициализационные «сеттеры», которые необходимо вызвать в GroupMembershipService , код растет довольно быстро, а PersonService теперь зависит не только от GroupMembershipService но и также все, от чего зависит GroupMembershipService . Кроме того, привязка к GroupMembershipService жестко закодирована в PersonService что означает, что вы не можете « PersonService для целей тестирования или использовать шаблон стратегии в разных частях приложения.

В случае инъекции зависимостей вместо создания экземпляра GroupMembershipService в вашем PersonService вы либо передадите его в конструктор PersonService , либо добавите свойство (getter и setter), чтобы установить его локальный экземпляр. Это означает, что вашему PersonService больше не нужно беспокоиться о том, как создать GroupMembershipService , он просто принимает те, которые ему даны, и работает с ними. Это также означает, что все, что является подклассом GroupMembershipService , или реализует интерфейс PersonService , может быть «введено» в PersonService , а PersonService не нужно знать об этом изменении.




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

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

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




This самое простое объяснение инжекционного впрыска зависимостей и зависимостей, которые я когда-либо видел:

Без инъекций зависимостей

  • Приложение требует Foo (например, контроллер), поэтому:
  • Приложение создает Foo
  • Заявки на вызов Foo
    • Foo нуждается в Bar (например, услуге), поэтому:
    • Foo создает бары
    • Foo calls Bar
      • Бар нуждается в Bim (услуге, репозитории, ...), поэтому:
      • Бар создает Bim
      • Бар делает что-то

С инъекцией зависимости

  • Приложение нуждается в Foo, которому нужен Bar, который нуждается в Bim, так что:
  • Приложение создает Bim
  • Приложение создает Bar и дает ему Bim
  • Приложение создает Foo и дает ему Bar
  • Заявки на вызов Foo
    • Foo calls Bar
      • Бар делает что-то

Использование контейнера для инъекций зависимостей

  • Приложение требует Foo так:
  • Приложение получает Foo из контейнера, поэтому:
    • Контейнер создает Bim
    • Контейнер создает Bar и дает ему Bim
    • Контейнер создает Foo и дает ему Bar
  • Заявки на вызов Foo
    • Foo calls Bar
      • Бар делает что-то

Инъекция зависимостей и зависимость Контейнеры для инъекций - это разные вещи:

  • Dependency Injection - метод для написания лучшего кода
  • Контейнер DI - это инструмент, помогающий инъекционным зависимостям

Вам не нужен контейнер для инъекций зависимостей. Однако контейнер может вам помочь.




Что такое инъекция зависимостей (DI)?

Как говорили другие, Dependency Injection (DI) снимает ответственность за непосредственное создание и управление продолжительностью жизни других экземпляров объектов, от которых зависит наш класс интересов (потребительский класс) (в смысле UML ). Эти экземпляры вместо этого передаются в наш потребительский класс, как правило, в качестве параметров конструктора или через средства определения свойств (управление экземпляром объекта зависимостей и переход к классу потребителей обычно выполняется контейнером инверсии управления (IoC) , но это еще одна тема) ,

DI, DIP и SOLID

В частности, в парадигме принципов SOLID, основанных на объектно-ориентированном дизайне Роберта К. Мартина, DI является одной из возможных реализаций принципа инверсии зависимостей (DIP) . DIP - это D SOLID mantra - другие реализации DIP включают в себя локатор сервисов и шаблоны плагинов.

Цель DIP состоит в том, чтобы разделить жесткие, конкретные зависимости между классами, а вместо этого ослабить связь посредством абстракции, которая может быть достигнута с помощью interface , abstract class или pure virtual class зависимости от используемого языка и подхода ,

Без DIP наш код (я назвал этот «потребительский класс») напрямую связан с конкретной зависимостью, а также часто обременен ответственностью за знание того, как получить и управлять экземпляром этой зависимости, то есть концептуально:

"I need to create/use a Foo and invoke method `GetBar()`"

Принимая во внимание, что после применения DIP требование ослабевает, а проблема получения и управления продолжительностью жизни Foo была устранена:

"I need to invoke something which offers `GetBar()`"

Зачем использовать DIP (и DI)?

Развязанные зависимости между классами таким образом позволяют легко подменять эти классы зависимостей на другие реализации, которые также выполняют предпосылки абстракции (например, зависимость может быть переключена с другой реализацией того же интерфейса). Более того, как отмечали другие, возможно, наиболее распространенная причина для развязки классов через DIP - это позволить тестировать класс потребления отдельно, так как эти же зависимости теперь можно окутать и / или высмеять.

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

Это можно посмотреть по-разному:

  • Если необходимо сохранить контроль жизненных циклов потребляющим классом, управление можно восстановить, введя (абстрактный) завод для создания экземпляров класса зависимостей в класс потребителя. Потребитель сможет получить экземпляры через Create на фабрике по мере необходимости и избавиться от этих экземпляров после завершения.
  • Или управление жизненным циклом экземпляров зависимостей может быть отказано от контейнера IoC (подробнее об этом ниже).

Когда использовать DI?

  • Там, где, вероятно, потребуется заменить зависимость для эквивалентной реализации,
  • Каждый раз, когда вам нужно будет тестировать методы класса в зависимости от его зависимостей,
  • В тех случаях, когда неопределенность в отношении продолжительности жизни зависит от экспериментов (например, Hey, MyDepClass является потокобезопасным - что, если мы сделаем его MyDepClass введем один и тот же экземпляр всем потребителям?)

пример

Вот простая реализация C #. Учитывая нижний класс потребления:

public class MyLogger
{
   public void LogRecord(string somethingToLog)
   {
      Console.WriteLine("{0:HH:mm:ss} - {1}", DateTime.Now, somethingToLog);
   }
}

Несмотря на кажущуюся безобидность, он имеет две static зависимости от двух других классов: System.DateTime и System.Console , которые не только ограничивают параметры вывода журнала (вход в консоль бесполезен, если никто не смотрит), но, что еще хуже, для автоматического тестирования с учетом зависимости от недетерминированных системных часов.

Тем не менее мы можем применить DIP к этому классу, абстрагировав озабоченность временной MyLogger как зависимость и MyLogger только с простым интерфейсом:

public interface IClock
{
    DateTime Now { get; }
}

Мы также можем ослабить зависимость от Console до абстракции, например TextWriter . Инъекция зависимостей обычно реализуется как либо впрыск constructor (передача абстракции в зависимость как параметр конструктору потребляющего класса), так и setXyz() Setter Injection (передача зависимости с помощью setXyz() setter или .Net Property с {set;} определены). Предпочтение от конструктора предпочтительнее, так как это гарантирует, что класс будет в правильном состоянии после построения и позволит полям внутренней зависимости быть помечены как readonly (C #) или final (Java). Поэтому, используя инъекцию конструктора в приведенном выше примере, это оставляет нам:

public class MyLogger : ILogger // Others will depend on our logger.
{
    private readonly TextWriter _output;
    private readonly IClock _clock;

    // Dependencies are injected through the constructor
    public MyLogger(TextWriter stream, IClock clock)
    {
        _output = stream;
        _clock = clock;
    }

    public void LogRecord(string somethingToLog)
    {
        // We can now use our dependencies through the abstraction 
        // and without knowledge of the lifespans of the dependencies
        _output.Write("{0:yyyy-MM-dd HH:mm:ss} - {1}", _clock.Now, somethingToLog);
    }
}

(Необходимо предоставить конкретные Clock , которые, конечно же, могут вернуться к DateTime.Now , и две зависимости должны быть предоставлены контейнером IoC через впрыск конструктора)

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

[Test]
public void LoggingMustRecordAllInformationAndStampTheTime()
{
    // Arrange
    var mockClock = new Mock<IClock>();
    mockClock.Setup(c => c.Now).Returns(new DateTime(2015, 4, 11, 12, 31, 45));
    var fakeConsole = new StringWriter();

    // Act
    new MyLogger(fakeConsole, mockClock.Object)
        .LogRecord("Foo");

    // Assert
    Assert.AreEqual("2015-04-11 12:31:45 - Foo", fakeConsole.ToString());
}

Следующие шаги

Инъекция зависимостей всегда связана с контейнером «Инверсия управления» (IoC) , для ввода (предоставления) конкретных экземпляров зависимостей и для управления экземплярами lifespan. Во время процесса конфигурирования / начальной загрузки контейнеры IoC позволяют определить следующее:

  • сопоставление между каждой абстракцией и сконфигурированной конкретной реализацией (например, «в любое время, когда потребитель запрашивает IBar , возвращает экземпляр ConcreteBar » )
  • политики могут быть настроены для управления жизненным циклом каждой зависимости, например, для создания нового объекта для каждого экземпляра потребителя, для совместного использования экземпляра зависимости Singleton для всех потребителей, для совместного использования одного экземпляра зависимостей только через один и тот же поток и т. д.
  • В .Net контейнеры IoC знают о протоколах, таких как IDisposable и берут на себя ответственность за Disposing зависимостей в соответствии с настроенным управлением продолжительностью жизни.

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

Ключом к DI-дружественному коду является предотвращение статической связи классов, а не использование new () для создания зависимостей

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

Но преимуществ много, особенно в способности тщательно протестировать ваш класс интересов.

Примечание . Создание / сопоставление / проецирование (через new ..()) DOC / POJO / Serialization DTOs / Entity Graphs / Анонимные прогнозы JSON и т. Д., Т.е. классы или записи только для данных, используемые или возвращенные из методов, не рассматриваются как зависимости (в UML) и не подвержены DI. Использование newдля проецирования это просто отлично.




Вся цель Injection Dependency Injection (DI) заключается в том, чтобы сохранить исходный код приложения чистым и стабильным :

  • очистить код инициализации зависимостей
  • стабильно независимо от используемой зависимости

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

Конкретным доменом DI является делегирование конфигурации зависимостей и инициализации.

Пример: DI со сценарием оболочки

Если вы иногда работаете за пределами Java, вспомните, как sourceчасто используется во многих языках сценариев (Shell, Tcl и т. Д., Или даже importв Python, для использования с этой целью).

Рассмотрим простой dependent.shскрипт:

#!/bin/sh
# Dependent
touch         "one.txt" "two.txt"
archive_files "one.txt" "two.txt"

Сценарий зависит: он не будет успешно выполнен сам по себе ( archive_filesне определен).

Необходимо определить archive_filesв archive_files_zip.shсценарии реализации ( с использованием zipв данном случае):

#!/bin/sh
# Dependency
function archive_files {
    zip files.zip "$@"
}

Вместо sourceсценария реализации непосредственно в зависимом, вы используете injector.sh«контейнер», который обертывает оба «компонента»:

#!/bin/sh 
# Injector
source ./archive_files_zip.sh
source ./dependent.sh

archive_files Зависимость только что была введена в зависимый сценарий.

Вы могли бы вводить зависимость, которая реализует archive_filesиспользование tarили xz.

Пример: удаление DI

Если dependent.shскрипт использовал зависимости напрямую, этот подход будет называться поиском зависимостей (который противоречит инъекции зависимостей ):

#!/bin/sh
# Dependent

# dependency look-up
source ./archive_files_zip.sh

touch         "one.txt" "two.txt"
archive_files "one.txt" "two.txt"

Теперь проблема заключается в том, что зависимый «компонент» должен выполнять инициализацию.

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

Последние слова

DI не так сильно подчеркивается и популяризируется, как в Java-инфраструктурах.

Но это общий подход для разделения проблем:

  • разработка приложений ( жизненный цикл выпуска с одним исходным кодом)
  • развертывание приложений ( несколько целевых сред с независимыми жизненными циклами)

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




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

DI для краткости, это метод устранения общей дополнительной ответственности (нагрузки) на компоненты для извлечения зависимых компонентов, путем предоставления им этого.

DI приближает вас к принципу единой ответственности (SR), например surgeon who can concentrate on surgery.

Когда использовать DI: я ​​бы рекомендовал использовать DI почти во всех производственных проектах (малый / большой), особенно в постоянно меняющихся бизнес-средах :)

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




Это означает, что объекты должны иметь только столько зависимостей, сколько необходимо для выполнения своей работы, а зависимостей должно быть немного. Кроме того, зависимости объекта должны быть от интерфейсов, а не от «конкретных» объектов, когда это возможно. (Конкретный объект - это любой объект, созданный с ключевым словом new.) Свободное соединение способствует большей возможности повторного использования, упрощает ремонтопригодность и позволяет вам легко создавать «макетные» объекты вместо дорогостоящих услуг.

«Инъекция зависимостей» (DI) также известна как «Инверсия управления» (IoC), которая может быть использована в качестве метода для поощрения этой свободной связи.

Существует два основных подхода к реализации DI:

  1. Впрыск конструктора
  2. Сетчатая инъекция

Впрыск конструктора

Это метод передачи зависимостей объектов с его конструктором.

Обратите внимание, что конструктор принимает интерфейс, а не конкретный объект. Также обратите внимание, что исключение вызывается, если параметр orderDao имеет значение NULL. Это подчеркивает важность получения действительной зависимости. Constructor Injection - это, на мой взгляд, предпочтительный механизм предоставления объекту его зависимостей. Это понятно разработчику при вызове объекта, зависимости которого должны быть переданы объекту «Человек» для правильного выполнения.

Впрыск сеттера

Но рассмотрим следующий пример ... Предположим, у вас есть класс с десятью методами, которые не имеют зависимостей, но вы добавляете новый метод, который имеет зависимость от IDAO. Вы можете изменить конструктор для использования Constructor Injection, но это может заставить вас внести изменения во все вызовы конструктора по всему месту. Кроме того, вы можете просто добавить новый конструктор, который принимает зависимость, но тогда как разработчик легко знает, когда использовать один конструктор над другим. Наконец, если зависимость очень дорога для создания, почему она должна быть создана и передана конструктору, когда ее можно использовать редко? «Setter Injection» - это еще один метод DI, который можно использовать в таких ситуациях.

Setter Injection не приводит к передаче зависимостей конструктору. Вместо этого зависимости устанавливаются на публичные свойства, которые подвергаются объекту, который в этом нуждается. Как предполагалось ранее, основными мотивами для этого являются:

  1. Поддержка инъекции зависимостей без необходимости изменения конструктора унаследованного класса.
  2. Разрешить создание дорогостоящих ресурсов или служб как можно позже и только в случае необходимости.

Вот пример того, как выглядел бы приведенный выше код:

public class Person {
    public Person() {}

    public IDAO Address {
        set { addressdao = value; }
        get {
            if (addressdao == null)
              throw new MemberAccessException("addressdao" +
                             " has not been initialized");
            return addressdao;
        }
    }

    public Address GetAddress() {
       // ... code that uses the addressdao object
       // to fetch address details from the datasource ...
    }

    // Should not be called directly;
    // use the public property instead
    private IDAO addressdao;



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

(и ps, да, это стало чрезмерно раздутым 25 $ именем для довольно простой концепции) , мои .25центы




Популярные ответы бесполезны, потому что они определяют инъекцию зависимости таким образом, что это не полезно. Согласитесь, что под «зависимостью» мы подразумеваем некоторый ранее существовавший другой объект, который нужен нашему объекту X. Но мы не говорим, что делаем «инъекцию зависимостей», когда говорим

$foo = Foo->new($bar);

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

«Инъекция зависимостей» считается типом «инверсии управления», а это означает, что из вызывающего абонента выводится некоторая логика. Это не тот случай, когда вызывающий абонент переходит в параметры, поэтому, если это DI, DI не будет означать инверсию управления.

DI означает, что между вызывающим и конструктором существует промежуточный уровень, который управляет зависимостями. Makefile - простой пример инъекции зависимостей. «Вызывающий» - это человек, который набирает «make bar» в командной строке, а «конструктор» - это компилятор. Файл Makefile указывает, что бар зависит от foo, и он выполняет

gcc -c foo.cpp; gcc -c bar.cpp

перед выполнением

gcc foo.o bar.o -o bar

Человек, набравший «make bar», не должен знать, что бар зависит от foo. Зависимость вводилась между «make bar» и gcc.

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

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




Инъекционная инъекция является одним из возможных решений того, что обычно можно назвать требованием «Зависимость обфускации». Зависимость Obfuscation - это метод принятия «очевидной» природы из процесса предоставления зависимости классу, который ее требует, и, следовательно, каким-то образом запутывает предоставление указанной зависимости указанному классу. Это не обязательно плохо. Фактически, путем запутывания способа предоставления зависимостям классу, то что-то вне класса отвечает за создание зависимости, что означает, что в разных сценариях может быть предоставлена ​​другая реализация зависимости, не внося никаких изменений к классу. Это отлично подходит для переключения между режимами производства и тестирования (например, с использованием зависимости «mock»).

К сожалению, плохая часть состоит в том, что некоторые люди предположили, что вам нужна специализированная инфраструктура для обфускации зависимостей и что вы как-то «менее» программист, если не хотите использовать определенную инфраструктуру для этого. Другим, чрезвычайно тревожным мифом, по мнению многих, является то, что инъекция зависимостей - единственный способ добиться запутывания зависимости. Это явно и исторически и, очевидно, на 100% неверно, но у вас возникнут проблемы с убеждением некоторых людей в том, что существуют альтернативы инъекции зависимостей для требований обфускации зависимостей.

Программисты поняли потребность в обфускации зависимостей в течение многих лет, и многие альтернативные решения эволюционировали как до, так и после инъекции зависимостей. Существуют шаблоны Factory, но также есть много вариантов, использующих ThreadLocal, где не требуется инъекция в конкретный экземпляр - зависимость эффективно внедряется в поток, который имеет преимущество в том, чтобы сделать доступный объект (через удобные статические методы getter) для любогокласс, который требует его, без необходимости добавлять аннотации к классам, которые его требуют, и создать сложный XML-клей, чтобы это произошло. Когда ваши зависимости требуются для настойчивости (JPA / JDO или что-то еще), это позволяет вам добиться «tranaparent persistence» намного проще и с классами модели домена и бизнес-модели, составленными исключительно из POJO (т. Е. Никакой специфической структуры / блокировки в аннотациях).




из книги Apress.Spring.Persistence.with.Hibernate.Oct.2010

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




В простых словах инъекция зависимостей (DI) - это способ удаления зависимостей или жесткой связи между разными объектами. Инъекция зависимостей дает когезионное поведение каждому объекту.

DI - это реализация принципала IOC от Spring, в котором говорится: «Не звоните нам, мы позвоним вам». Использование программиста для инъекций зависимостей не требуется для создания объекта с использованием нового ключевого слова.

Объекты загружаются в контейнер Spring, а затем мы их повторно используем, когда нам это нужно, путем извлечения этих объектов из контейнера Spring с использованием метода getBean (String beanName).




Инъекция зависимостей (DI) является частью практики принципа инверсии зависимостей (DIP), которая также называется Inversion of Control (IoC). В основном вам нужно сделать DIP, потому что вы хотите сделать свой код более модульным и единым тестируемым, а не только одной монолитной системой. Итак, вы начинаете идентифицировать части кода, которые можно отделить от класса и отвлечь. Теперь выполнение абстракции нужно вводить извне класса. Обычно это можно сделать с помощью конструктора. Таким образом, вы создаете конструктор, который принимает абстракцию как параметр, и это называется инъекцией зависимостей (через конструктор). Для получения дополнительной информации о контейнере DIP, DI и IoC вы можете прочитать Here




Я бы предложил немного другое, короткое и точное определение того, что такое инъекция зависимостей, сосредоточившись на основной цели, а не на технических средствах (следуя here ):

Dependency Injection - это процесс создания статического графика без атрибутов объектов службы, где каждая служба параметризуется своими зависимостями.

Объекты, которые мы создаем в наших приложениях (независимо от того, используем ли я Java, C # или другой объектно-ориентированный язык), обычно попадают в одну из двух категорий: статические и глобальные «объекты обслуживания» (модули), а также состояния, динамические и локальные «Объекты данных».

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

Одним из требований является то, что услуги должны быть параметризованы их зависимостями. То, что это означает, в точности зависит от языка и подхода, применяемого в данной системе. Обычно это принимает форму параметров конструктора, но использование настроек также является опцией. Это также означает, что зависимости службы скрыты (при вызове метода услуги) от пользователей службы.

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




Related