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

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

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

30 ответов


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

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

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

Это может быть хлопотно, когда все, что вы хотите сделать, это запустить некоторые модульные тесты на SomeClass, особенно если myObject-это то, что делает сложный доступ к диску или сети. Итак, теперь вы смотрите на насмешливый myObject, но также каким-то образом перехватываете заводской вызов. Трудный. Вместо этого передайте объект в качестве аргумента конструктор. Теперь вы переместили проблему в другое место, но тестирование может стать намного проще. Просто сделайте манекен myObject и передайте это. Конструктор теперь будет выглядеть примерно так:

public SomeClass (MyClass myObject) {
    this.myObject = myObject;
}

Это один стиль инъекции зависимостей через конструктор. Возможны несколько механизмов.

  • как отмечено в комментариях, одна из распространенных альтернатив-определить конструктор ничего не делать и ввести зависимости с помощью установщиков свойств (h/t @MikeVella).
  • Мартин Фаулер документирует третью альтернативу (h/t @MarcDix), где классы явно реализуют интерфейс для зависимостей, которые они хотят ввести.

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

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


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

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

здесь статья Мартина Фаулера это тоже может оказаться полезным.

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

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


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

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

например,Car объект.

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


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

например, рассмотрим следующие классы:

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 имеет несколько вещей, которые он требует, или еще хуже, есть некоторые инициализации "сеттеры", которые должны быть вызваны на GroupMembershipService, код растет, а быстро, и PersonService теперь зависит не только от GroupMembershipService, но и все остальное, что GroupMembershipService зависит от. Кроме того, связь с GroupMembershipService содержащееся в PersonService что означает, что вы не можете "подделать" a GroupMembershipService для целей тестирования или для использования шаблона стратегии в разных частях вашего приложения.

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


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

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

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


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

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

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


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

public class Car
{
    public Car()
    {
        GasEngine engine = new GasEngine();
        engine.Start();
    }
}

public class GasEngine
{
    public void Start()
    {
        Console.WriteLine("I use gas as my fuel!");
    }
}

и для создания экземпляра класса Car мы будем использовать следующий код:

Car car = new Car();

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

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

    public interface IEngine
    {
        void Start();
    }

    public class GasEngine : IEngine
    {
        public void Start()
        {
            Console.WriteLine("I use gas as my fuel!");
        }
    }

    public class ElectricityEngine : IEngine
    {
        public void Start()
        {
            Console.WriteLine("I am electrocar");
        }
    }

    public class Car
    {
        private readonly IEngine _engine;
        public Car(IEngine engine)
        {
            _engine = engine;
        }

        public void Run()
        {
            _engine.Start();
        }
    }

теперь наш класс автомобиля зависит только на интерфейсе IEngine, а не на конкретной реализации engine. Теперь единственный трюк заключается в том, как мы создаем экземпляр автомобиля и даем ему реальный конкретный класс двигателя, такой как GasEngine или ElectricityEngine. Вот где Инъекции Зависимостей приходит.

   Car gasCar = new Car(new GasEngine());
   gasCar.Run();
   Car electroCar = new Car(new ElectricityEngine());
   electroCar.Run();

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

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

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

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

обновление: недавно смотрел курс об EF Core от Джули Лерман, а также понравилось ее короткое определение о DI.

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


этой самое простое объяснение о Инъекции Зависимостей и Контейнер Для Инъекций Зависимостей Я когда-либо видел:

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

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

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

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

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

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

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

  • инъекция зависимостей-это метод для написания лучшего кода
  • контейнер DI инструмент для того чтобы помочь впрыскивать зависимости

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


не означает ли "инъекция зависимостей" просто использование параметризованных конструкторов и общедоступных сеттеров?

статья Джеймса Шора показывает следующие примеры для сравнения.

конструктор без инъекции зависимостей:

public class Example { 
  private DatabaseThingie myDatabase; 

  public Example() { 
    myDatabase = new DatabaseThingie(); 
  } 

  public void doStuff() { 
    ... 
    myDatabase.getData(); 
    ... 
  } 
} 

конструктор с инъекцией зависимостей:

public class Example { 
  private DatabaseThingie myDatabase; 

  public Example(DatabaseThingie useThisDatabaseInstead) { 
    myDatabase = useThisDatabaseInstead; 
  }

  public void doStuff() { 
    ... 
    myDatabase.getData(); 
    ... 
  } 
}

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

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

DI, DIP и SOLID

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

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

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

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

тогда как после применения погружения, требование отпущено, и забота получать и управлять продолжительность жизни Foo зависимость удалена:

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

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

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

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

это можно рассматривать по-разному:

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

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

  • где, вероятно, будет необходимость заменить зависимость на эквивалентную реализация,
  • в любое время, когда вам нужно будет проверить методы класса в изоляции его зависимостей,
  • где неопределенность продолжительности жизни зависимости может потребовать экспериментов (например, Hey,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 к этому классу, абстрагируясь от проблемы timestamping как зависимости, и сцепление!--19--> только для простого интерфейса:

public interface IClock
{
    DateTime Now { get; }
}

мы также можем ослабить зависимость Console к абстракции, такой как TextWriter. Инъекция зависимостей обычно реализуется как constructor injection (передача абстракции зависимости в качестве параметра конструктору потребляющего класса) или Setter Injection (передача зависимости через setXyz() сеттер или свойство .Net с {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), вводить (предоставлять) конкретные экземпляры зависимостей и управлять экземплярами продолжительности жизни. Во время процесса настройки / начальной загрузки, IoC контейнеры позволяют определить следующее:

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

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

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

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

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

Примечание: создание / отображение / проекция (через new ..()) POCO / POJO / Serialization DTOs / Entity Graphs / Anonymous JSON projections et al-т. е." только данные " классы или записи-используются или возвращаются из методов не рассматривается как зависимости (в смысле UML) и не подлежит DI. Используя new проецировать их просто отлично.


чтобы сделать концепцию инъекции зависимостей простой для понимания. Давайте возьмем пример кнопки переключения для переключения (включения/выключения) лампы.

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

переключатель должен знать заранее, к какой лампочке я подключен (жестко закодированная зависимость). Итак,

Переключатель -> PermanentBulb //переключатель непосредственно подключен к постоянной лампе, тестирование невозможно легко

Switch(){
PermanentBulb = new Bulb();
PermanentBulb.Toggle();
}

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

переключатель только знает, что мне нужно включить / выключить любую лампочку, переданную мне. Итак,

переключатель - > Bulb1 или Bulb2 или NightBulb (инъекционная зависимость)

Switch(AnyBulb){ //pass it whichever bulb you like
AnyBulb.Toggle();
}

модификации Джеймс пример для переключателя и лампы:

public class SwitchTest { 
  TestToggleBulb() { 
    MockBulb mockbulb = new MockBulb(); 

    // MockBulb is a subclass of Bulb, so we can 
    // "inject" it here: 
    Switch switch = new Switch(mockBulb); 

    switch.ToggleBulb(); 
    mockBulb.AssertToggleWasCalled(); 
  } 
}

public class Switch { 
  private Bulb myBulb; 

  public Switch() { 
    myBulb = new Bulb(); 
  } 

  public Switch(Bulb useThisBulbInstead) { 
    myBulb = useThisBulbInstead; 
  } 

  public void ToggleBulb() { 
    ... 
    myBulb.Toggle(); 
    ... 
  } 
}`

весь смысл инъекции зависимостей (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-ing сценарий реализации непосредственно в зависимом, вы используете injector.sh "контейнер", который обертывает, как "компоненты":

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

на archive_files зависимость только injected на зависимая сценарий.

вы могли бы ввести зависимость, которая реализует 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"

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

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

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

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

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

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

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


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

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

как инъекция зависимости работает весной:

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

инверсии контроля (IOC)

МОК является общей концепцией, и она может быть выражена различными способами, и инъекция зависимостей является одним из конкретных примеров МОК.

два типа инъекции зависимостей:

  1. Конструктор Инъекций
  2. сеттер Инъекция

1. Инъекция зависимостей на основе конструктора:

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

public class Triangle {

private String type;

public String getType(){
    return type;
 }

public Triangle(String type){   //constructor injection
    this.type=type;
 }
}
<bean id=triangle" class ="com.test.dependencyInjection.Triangle">
        <constructor-arg value="20"/>
  </bean>

2. Инъекция зависимостей на основе сеттера:

Setter-based DI выполняется контейнером, вызывающим методы setter на ваших бобах после вызова конструктора без аргумента или статического без аргумента заводской метод для создания экземпляра вашего bean.

public class Triangle{

 private String type;

 public String getType(){
    return type;
  }
 public void setType(String type){          //setter injection
    this.type = type;
  }
 }

<!-- setter injection -->
 <bean id="triangle" class="com.test.dependencyInjection.Triangle">
        <property name="type" value="equivialteral"/>

Примечание.: Хорошее эмпирическое правило-использовать аргументы конструктора для обязательных зависимостей и сеттеры для необязательных зависимостей. Обратите внимание, что если мы используем аннотацию, основанную на @Required аннотации на сеттере, можно использовать для создания сеттеров в качестве требуемых зависимостей.


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

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

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

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


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

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

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

Reel-to-reel portable tape recorder, mid-20th century.

вышеуказанное изображение изображение вьюрка-к-вьюрка портативного магнитофона, середины 20th века. источник.

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

главные преимущества нам удалось достичь с помощью внедрения зависимостей.

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

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

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

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

ранее мы писали такой код

Public MyClass{
 DependentClass dependentObject
 /*
  At somewhere in our code we need to instantiate 
  the object with new operator  inorder to use it or perform some method.
  */ 
  dependentObject= new DependentClass();
  dependentObject.someMethod();
}

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

Public MyClass{
 /* Dependency injector will instantiate object*/
 DependentClass dependentObject

 /*
  At somewhere in our code we perform some method. 
  The process of  instantiation will be handled by the dependency injector
 */ 

  dependentObject.someMethod();
}

вы может также читать

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


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

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

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

  1. конструктор инъекций
  2. сеттер инъекций

конструктор инъекций

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

обратите внимание, что конструктор принимает интерфейс, а не конкретный объект. Также обратите внимание, что исключение создается, если параметр orderDao имеет значение null. Это подчеркивает важность получения действительной зависимости. Инъекция конструктора, на мой взгляд, является предпочтительным механизмом для предоставления объекту его зависимостей. Разработчику ясно при вызове объекта, какие зависимости необходимо предоставить объекту "лицо" для надлежащего выполнения.

Сеттер Инъекций

но рассмотрим следующий пример... Предположим, у вас есть класс с десятью методами, которые не имеют зависимостей, но вы добавляете новый метод, который имеет зависимость от IDAO. Вы можете изменить конструктор для использования инъекции конструктора, но это может заставить вас изменить все вызовы конструктора повсюду. Кроме того, вы можете просто добавить новый конструктор, который принимает зависимость, но тогда как разработчик легко знает, когда использовать один конструктор над другим. Наконец, если зависимость очень дорогая для создания, почему она должна быть создан и передан конструктору, когда он может использоваться редко? "Впрыска сеттера" другой метод Ди который можно использовать в ситуациях как это.

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

  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;

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

  1. когда у вас есть конфигурация DI, где все фактические реализации (не интерфейсы), которые будут введены в класс (для e.G услуги контроллеру) почему это не какое-то жесткое кодирование?
  2. Что делать, если я хочу изменить объект во время выполнения? Например, моя конфигурация уже говорит, Когда я создаю экземпляр MyController, inject for FileLogger как ILogger. Но я могу ... хотите ввести DatabaseLogger.
  3. каждый раз, когда я хочу изменить то, что нужно моему AClass, мне нужно теперь посмотреть в два места - сам класс и файл конфигурации. Как это облегчает жизнь?
  4. Если Aproperty AClass не впрыснуто, то более трудно насмехаться оно вне?
  5. возвращаясь к первому вопросу. Если использование new object () плохо, почему мы вводим реализацию, а не интерфейс? Я думаю, многие из вас говорят, что мы на самом деле инъекция интерфейса, но конфигурация заставляет вас указать реализацию этого интерфейса ..не во время выполнения .. он жестко закодирован во время компиляции.

это основано на ответе @Adam N posted.

Почему PersonService больше не нужно беспокоиться о GroupMembershipService? Вы только что упомянули, что GroupMembership имеет несколько вещей (объектов/свойств), от которых он зависит. Если бы GMService был необходим в PService, вы бы имели его как свойство. Ты можешь насмехаться над этим. вне зависимости от того, сделали вы инъекцию или нет. Единственный раз, когда я хотел бы, чтобы он был введен, - это если бы GMService имел более конкретные дочерние классы,которые вы не знали бы до выполнения. Тогда вы захотите ввести подкласс. Или если вы хотите использовать это как синглтон или прототип. Честно говоря, файл конфигурации имеет все жестко закодированное, насколько подкласс для типа (интерфейса) он собирается вводить во время компиляции.

редактировать

хороший комментарий Хосе Мария Арранс на ди

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

False. Направление зависимостей в форме XML или в виде аннотаций, ваши зависимости записываются в виде XML-кода и аннотаций. XML и аннотации являются исходным кодом.

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

False. Для построения модульного кода на основе интерфейсов не требуется платформа DI.

о заменяемом: с очень простым .свойства архив и класс.forName вы можете определить, какие классы могут изменяться. Если какой-либо класс вашего кода можно изменить, Java не для вас, используйте язык сценариев. Кстати: аннотации нельзя изменить без перекомпиляции.

на мой взгляд есть одна единственная причина для рамок DI: уменьшение плиты боилера. С хорошо сделанной фабричной системой вы можете сделать то же самое, более контролируемое и более предсказуемое, как ваш предпочтительный di framework, di Framework обещает сокращение кода (XML и аннотации также являются исходным кодом). Проблема в том, что это сокращение котельной плиты просто реально в очень простых случаях( один экземпляр-на класс и тому подобное), иногда в реальном мире выбор соответствующего объекта обслуживания не так просто, как сопоставление класса с одноэлементным объект.


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

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


Я знаю, что уже есть много ответов, но я нашел это очень полезным:http://tutorials.jenkov.com/dependency-injection/index.html

Нет Зависимости:

public class MyDao {

  protected DataSource dataSource =
    new DataSourceImpl("driver", "url", "user", "password");

  //data access methods...
  public Person readPerson(int primaryKey) {...}

}

зависимость:

public class MyDao {

  protected DataSource dataSource = null;

  public MyDao(String driver, String url, String user, String
 password){
    this.dataSource = new DataSourceImpl(driver, url, user, password);
  }

  //data access methods...
  public Person readPerson(int primaryKey)
  {...}

}

обратите внимание, как DataSourceImpl экземпляр перемещается в конструктор. Конструктор принимает четыре параметра, которые являются четырьмя значениями, необходимыми для DataSourceImpl. Хотя ... --4--> класс по-прежнему зависит от этих четырех значений, он больше не удовлетворяет эти зависимости сам. Они предоставляются любым классом, создающим MyDao экземпляра.


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

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

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

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

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

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

перед

gcc foo.o bar.o -o bar

человек, набрав "make bar", не должен знать, что бар зависит от foo. Зависимость была введена между "make bar" и gcc.

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

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


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

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

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


из книги, 'хорошо обоснованный Разработчик Java: жизненно важные методы программирования Java 7 и полиглот

DI-это особая форма IoC, в которой процесс поиска ваших зависимостей вне прямого контроля вашего текущего кода.


пример, у нас есть 2 класса Client и Service. Client использовать Service

public class Service {
    public void doSomeThingInService() {
        // ...
    }
}

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

Способ 1)

public class Client {
    public void doSomeThingInClient() {
        Service service = new Service();
        service.doSomeThingInService();
    }
}

Способ 2)

public class Client {
    Service service = new Service();
    public void doSomeThingInClient() {
        service.doSomeThingInService();
    }
}

путь 3)

public class Client {
    Service service;
    public Client() {
        service = new Service();
    }
    public void doSomeThingInClient() {
        service.doSomeThingInService();
    }
}

1) 2) 3) Используя

Client client = new Client();
client.doSomeThingInService();

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

  • простой

недостатки

  • трудно для теста Client класс
  • когда мы меняем Service конструктор, нам нужно изменить код во всех местах create Service объект

Использовать Инъекцию Зависимостей

Способ 1) конструктор инъекция

public class Client {
    Service service;

    Client(Service service) {
        this.service = service;
    }

    // Example Client has 2 dependency 
    // Client(Service service, IDatabas database) {
    //    this.service = service;
    //    this.database = database;
    // }

    public void doSomeThingInClient() {
        service.doSomeThingInService();
    }
}

используя

Client client = new Client(new Service());
// Client client = new Client(new Service(), new SqliteDatabase());
client.doSomeThingInClient();

Способ 2) сеттер инъекций

public class Client {
    Service service;

    public void setService(Service service) {
        this.service = service;
    }

    public void doSomeThingInClient() {
        service.doSomeThingInService();
    }
}

используя

Client client = new Client();
client.setService(new Service());
client.doSomeThingInClient();

путь 3) укол интерфейс

проверить https://en.wikipedia.org/wiki/Dependency_injection

===

Сейчас этот код уже следовать Dependency Injection и легче для теста Client класс.
Однако мы все еще используем new Service() много времени и не хорошо когда изменение Service конструктор. Чтобы предотвратить это, мы можем использовать инжектор DI, как
1) простой ручной Injector

public class Injector {
    public static Service provideService(){
        return new Service();
    }

    public static IDatabase provideDatatBase(){
        return new SqliteDatabase();
    }
    public static ObjectA provideObjectA(){
        return new ObjectA(provideService(...));
    }
}

используя

Service service = Injector.provideService();

2) используйте библиотеку: для Android dagger2

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

  • сделать тест проще
  • при изменении Service, вам только нужно изменить это в классе инжектора
  • если вы используете use Constructor Injection, когда вы смотрите на конструктор Client, вы увидите, сколько зависимостей Client класс

недостатки

  • если вы используете use Constructor Injection на Service объект создается, когда Client создано, когда-то мы используем функцию в Client класса без использования Service создал Service потрачено

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

https://en.wikipedia.org/wiki/Dependency_injection

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


из книги Apress.Весна.Стойкость.с.Зимовать.Октябрь.2010

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


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

интерфейс:

package com.deepam.hidden;

public interface BookInterface {

public BookInterface setHeight(int height);
public BookInterface setPages(int pages);   
public int getHeight();
public int getPages();  

public String toString();
}

Далее у нас может быть много видов книг; один из типов-фантастика:

package com.deepam.hidden;

public class FictionBook implements BookInterface {
int height = 0; // height in cm
int pages = 0; // number of pages

/** constructor */
public FictionBook() {
    // TODO Auto-generated constructor stub
}

@Override
public FictionBook setHeight(int height) {
  this.height = height;
  return this;
}

@Override
public FictionBook setPages(int pages) {
  this.pages = pages;
  return this;      
}

@Override
public int getHeight() {
    // TODO Auto-generated method stub
    return height;
}

@Override
public int getPages() {
    // TODO Auto-generated method stub
    return pages;
}

@Override
public String toString(){
    return ("height: " + height + ", " + "pages: " + pages);
}
}

теперь абонент может иметь связь с книгой:

package com.deepam.hidden;

import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;

public class Subscriber {
BookInterface book;

/** constructor*/
public Subscriber() {
    // TODO Auto-generated constructor stub
}

// injection I
public void setBook(BookInterface book) {
    this.book = book;
}

// injection II
public BookInterface setBook(String bookName) {
    try {
        Class<?> cl = Class.forName(bookName);
        Constructor<?> constructor = cl.getConstructor(); // use it for parameters in constructor
        BookInterface book = (BookInterface) constructor.newInstance();
        //book = (BookInterface) Class.forName(bookName).newInstance();
    } catch (InstantiationException e) {
        e.printStackTrace();
    } catch (IllegalAccessException e) {
        e.printStackTrace();
    } catch (ClassNotFoundException e) {
        e.printStackTrace();
    } catch (NoSuchMethodException e) {
        e.printStackTrace();
    } catch (SecurityException e) {
        e.printStackTrace();
    } catch (IllegalArgumentException e) {
        e.printStackTrace();
    } catch (InvocationTargetException e) {
        e.printStackTrace();
    }
    return book;
}

public BookInterface getBook() {
  return book;
}

public static void main(String[] args) {

}

}

все три класса могут быть скрыты для его собственной реализации. Теперь мы можем использовать этот код для Ди:

package com.deepam.implement;

import com.deepam.hidden.Subscriber;
import com.deepam.hidden.FictionBook;

public class CallHiddenImplBook {

public CallHiddenImplBook() {
    // TODO Auto-generated constructor stub
}

public void doIt() {
    Subscriber ab = new Subscriber();

    // injection I
    FictionBook bookI = new FictionBook();
    bookI.setHeight(30); // cm
    bookI.setPages(250);
    ab.setBook(bookI); // inject
    System.out.println("injection I " + ab.getBook().toString());

    // injection II
    FictionBook bookII = ((FictionBook) ab.setBook("com.deepam.hidden.FictionBook")).setHeight(5).setPages(108); // inject and set
    System.out.println("injection II " + ab.getBook().toString());      
}

public static void main(String[] args) {
    CallHiddenImplBook kh = new CallHiddenImplBook();
    kh.doIt();
}
}

существует много разных способов использования инъекции зависимостей. Возможно совместить его с Синглтон и др., но все же в basic это только ассоциация, реализованная путем создания атрибута типа объекта внутри другого объекта. Полезность только и только в том, что код, который мы должны писать снова и снова, всегда готов и делается для нас вперед. Вот почему DI так тесно связан с инверсией управления (IoC), что означает, что наша программа передает управление другому работающему модулю, который делает инъекции бобов в наш код. (Каждый объект, который может быть введен, может быть подписан или считается Бобом.) Например, весной это делается путем создания и инициализации ApplicationContext контейнер, который делает эту работу за нас. Мы просто в нашем коде создаем контекст и вызываем инициализацию бобов. В этот момент инъекция была сделана автоматически.


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

DI-это реализация принципа МОК весны, который говорит:"Не звоните нам, мы позвоним вам". С помощью dependency injection programmer не нужно создавать объект с помощью нового ключевого слова.

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


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

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

ИНЪЕКЦИЯ ЗАВИСИМОСТЕЙ-ЭТО ПРОСТО СКЛЕИВАНИЕ ДВУХ КЛАССОВ И В ТО ЖЕ ВРЕМЯ ИХ РАЗДЕЛЕНИЕ.


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


Инъекции Зависимостей является типом реализации "инверсия управления " принцип, на котором базируется построение фреймворков.

рамки как указано в" шаблоне проектирования " GoF, это классы, которые реализуют основную логику потока управления, поднимающую разработчика для этого, таким образом, фреймворки реализуют инверсию принципа управления.

способ реализации как метода, а не как иерархии классов, это IoC принцип это просто инъекция зависимости.

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

экземпляры классов в "зависимости", внешняя привязка вызывающего компонента с экземпляром класса через ссылку является "инъекции".

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

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

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


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

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

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

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

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

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