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

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

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

2670
задан AR. 25 сент. '08 в 3:28
источник поделиться

32 ответов

  • 1
  • 2

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

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

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

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

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

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

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

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

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

1657
ответ дан wds 25 сент. '08 в 3:49
источник поделиться

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

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

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

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

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

2077
ответ дан Thiago Arrais 26 сент. '08 в 19:50
источник поделиться

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

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

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

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

Без инъекции зависимостей (DI):

class Car{
  private Wheel wh = new NepaliRubberWheel();
  private Battery bt = new ExcideBattery();

  //The rest
}

Здесь объект Car отвечает за создание зависимых объектов.

Что делать, если мы хотим изменить тип его зависимого объекта - скажем, Wheel - после начального NepaliRubberWheel()? Нам нужно воссоздать объект Car с его новой зависимостью, например ChineseRubberWheel(), но только производитель Car может это сделать.

Тогда что делает Dependency Injection для нас...?

При использовании инъекции зависимостей объекты получают свои зависимости во время выполнения, а не время компиляции (время изготовления автомобиля). Чтобы мы теперь могли менять Wheel когда захотим. Здесь dependency (wheel) может быть введена в Car во время выполнения.

После использования инъекции зависимостей:

Здесь мы вводим зависимости (Wheel and Battery) во время выполнения. Следовательно, термин "Инъекция зависимостей".

class Car{
  private Wheel wh = [Inject an Instance of Wheel (dependency of car) at runtime]
  private Battery bt = [Inject an Instance of Battery (dependency of car) at runtime]
  Car(Wheel wh,Battery bt) {
      this.wh = wh;
      this.bt = bt;
  }
  //Or we can have setters
  void setWheel(Wheel wh) {
      this.wh = wh;
  }
}

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

513
ответ дан gtiwari333 22 мая '11 в 7:01
источник поделиться

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

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

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

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

235
ответ дан Adam Ness 25 сент. '08 в 9:49
источник поделиться

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

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

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

143
ответ дан zby 06 янв. '11 в 21:33
источник поделиться

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

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

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

97
ответ дан Olivier Liechti 22 окт. '12 в 7:47
источник поделиться

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

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, нам нужно будет переписать класс Car. И чем больше приложение, тем больше проблем и головной боли нам придется добавлять и использовать новый тип движка.

Другими словами, при таком подходе наш класс высокого класса Car зависит от класса GasEngine более низкого уровня, который нарушает принцип инверсии зависимостей (DIP) от SOLID. 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();
        }
    }

Теперь наш класс Car зависит только от интерфейса IEngine, а не от конкретной реализации движка. Теперь единственным трюком является то, как мы создаем экземпляр автомобиля и даем ему настоящий конкретный класс двигателя, такой как GasEngine или ElectricityEngine. Это где Инъекция зависимостей.

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

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

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

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

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

ОБНОВЛЕНИЕ: Недавно просмотрел курс о EF Core от Джули Лерман, а также понравилось ее краткое определение о DI.

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

81
ответ дан user2771704 06 июля '17 в 12:42
источник поделиться

Это является самым простым объяснением Инъекции зависимостей и Контейнера для инъекций зависимостей. Я когда-либо видел:

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

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

с впрыском зависимостей

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

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

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

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

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

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

80
ответ дан Trix 05 мая '16 в 14:53
источник поделиться

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

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

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

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(); 
    ... 
  } 
}
45
ответ дан JaneGoodall 02 мая '13 в 3:40
источник поделиться

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

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

DI, DIP и SOLID

В частности, в парадигме Robert C Martin SOLID принципы объектно-ориентированного дизайна, DI является одной из возможных реализаций Принцип инверсии зависимостей (DIP). DIP - это D мантры SOLID - другие реализации 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 является то, что управление жизненным циклом экземпляров объекта зависимостей больше не контролируется классом-потребителем, так как объект зависимости теперь передается в класс потребления (через инсталляцию конструктора или сеттера).

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

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

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

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

Пример

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

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 как зависимости и связывая MyLogger только с простым интерфейсом:

public interface IClock
{
    DateTime Now { get; }
}

Мы также можем ослабить зависимость от Console до абстракции, такой как a TextWriter. Инъекция зависимостей обычно реализуется как либо constructor инъекция (передача абстракции зависимости в качестве параметра для конструктора потребляющего класса), так и Setter Injection (передача зависимости с помощью установщика setXyz() или .Net Property с {set;}). Предпочтительным является инжектор конструктора, так как это гарантирует, что после построения класс будет в правильном состоянии и позволит поля внутренней зависимости быть помечены как readonly (С#) или 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 через впрыск конструктора)

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

[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());
}

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

Инъекция зависимостей неизменно связана с Inversion of Control container (IoC), чтобы вводить (предоставлять) конкретные экземпляры зависимостей и управлять сроки жизни. Во время процесса конфигурирования/начальной загрузки контейнеры IoC допускают следующее:

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

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

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

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

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

Примечание: создание/отображение/проецирование (через new ..()) POCO/POJO/сериализации DTO/диаграммы сущностей/анонимные прогнозы JSON и др. - т.е. классы или записи только для данных - используемые или возвращенные из методов, не рассматриваются как Зависимости (в смысле UML) и не подлежат DI. Использование new для проецирования их просто отлично.

34
ответ дан StuartLC 28 апр. '15 в 23:17
источник поделиться

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

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

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

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

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

С впрыском зависимостей

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

Switch → Bulb1 ИЛИ Bulb2 OR NightBulb (вложенная зависимость)

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

Изменение James Пример для переключателя и лампы:

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(); 
    ... 
  } 
}`
30
ответ дан wakqasahmed 28 окт. '16 в 23:30
источник поделиться

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

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

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

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

Пример: DI с оболочкой script

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

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

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

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

Вы определяете archive_files в archive_files_zip.sh реализации script (используя zip в этом случае):

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

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

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

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

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

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

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

#!/bin/sh
# Dependent

# dependency look-up
source ./archive_files_zip.sh

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

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

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

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

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

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

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

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

23
ответ дан uvsmtid 23 сент. '13 в 19:28
источник поделиться

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

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

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

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

Инверсия управления (IOC)

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

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

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

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. Нагрузка зависимостей на основе сеттера:

Integer DI выполняется с помощью методов вызова контейнера на вашем beans после вызова конструктора no-argument или без аргумента static factory для создания экземпляра 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 аннотации на сеттер, можно использовать для создания сеттеров в качестве необходимых зависимостей.

17
ответ дан Harleen 04 дек. '15 в 8:50
источник поделиться

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

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

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

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

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

15
ответ дан Anwar Husain 05 апр. '16 в 19:15
источник поделиться

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

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

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

  • Ввод конструктора
  • Узел установки

Ввод конструктора

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

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

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

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

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

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

Вот пример того, как выглядит следующий код:

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;
13
ответ дан Piyush Deshpande 07 янв. '14 в 14:45
источник поделиться

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

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

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

Портативный магнитофон с катушкой на катушку, середина 20 века.

Вышеприведенное изображение представляет собой изображение портативного магнитофона Reel-to-reel, середина 20-го века. Источник.

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

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

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

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

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

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

Раньше мы пишем такой код

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();
}

Вы также можете прочитать

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

13
ответ дан Samuel J Mathew 03 нояб. '17 в 10:36
источник поделиться

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

  • Если у вас есть конфигурация DI, где все фактические реализации (а не интерфейсы), которые будут внедрены в класс (например, службы для контроллера), почему это не какое-то жесткое кодирование?
  • Что делать, если я хочу изменить объект во время выполнения? Например, моя конфигурация уже говорит, когда я создаю экземпляр MyController, вставляю FileLogger как ILogger. Но я могу захотеть ввести DatabaseLogger.
  • Каждый раз, когда я хочу изменить те объекты, которые мне нужны в AClass, мне нужно теперь изучить два места: сам класс и файл конфигурации. Как это облегчает жизнь?
  • Если Aproperty из AClass не вводится, сложнее ли это издеваться?
  • Возвращаясь к первому вопросу. Если использование нового объекта() плохое, почему мы внедряем реализацию, а не интерфейс? Я думаю, многие из вас говорят, что мы на самом деле вводим интерфейс, но в конфигурации вы указываете реализацию этого интерфейса. Не во время выполнения. Он жестко запрограммирован во время компиляции.

Это основано на ответе @Adam N.

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

EDIT

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

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

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

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

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

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

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

10
ответ дан Chookoos 25 окт. '13 в 6:56
источник поделиться

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

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

8
ответ дан Nikos M. 10 дек. '15 в 18:50
источник поделиться

Популярные ответы бесполезны, потому что они определяют инъекцию зависимости таким образом, что это не полезно. Согласитесь, что под "зависимостью" мы подразумеваем некоторый ранее существовавший другой объект, который нужен нашему объекту 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.

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

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

7
ответ дан Phil Goetz 02 июня '15 в 21:09
источник поделиться

Я знаю, что ответов уже много, но я нашел это очень полезным: 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. Хотя класс MyDao все еще зависит от этих четырех значений, он больше не удовлетворяет этим зависимостям. Они предоставляются любым классом, создающим экземпляр MyDao.

7
ответ дан Ali Issa 12 нояб. '14 в 17:37
источник поделиться

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

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

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

6
ответ дан Volksman 02 апр. '14 в 1:21
источник поделиться

Из книги, Хорошо обоснованный Java-разработчик: жизненные приемы программирования Java 7 и полиглота

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

5
ответ дан TastyCode 18 мая '13 в 22:27
источник поделиться

Например, у нас есть 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, нам нужно изменить код на месте, создайте объект 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, вам нужно только изменить его в классе Injector
  • Если вы используете использование Constructor Injection, когда вы смотрите на конструктор Client, вы увидите, сколько зависимостей класса Client

Недостатки

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

Определение впрыска зависимости

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

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

4
ответ дан Phan Van Linh 14 марта '18 в 7:41
источник поделиться

Инъекция зависимостей (DI) является одной из шаблонов проектирования, в которой используется базовая функция OOP - отношения в одном объекте с другим объектом. Хотя наследование наследует один объект для создания более сложного и конкретного другого объекта, отношения или ассоциации просто создают указатель на другой объект из одного объекта с использованием атрибута. Мощность 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) {

}

}

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

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();
}
}

Существует множество способов использования инъекции зависимостей. Можно объединить его с Singleton и т.д., Но все же в базовом это только ассоциация, реализуемая путем создания атрибута типа объекта внутри другого объекта. Полезность только и только в функции, этот код, который мы должны писать снова и снова, всегда готов и сделан для нас вперед. Вот почему DI так тесно связан с Inversion of Control (IoC), что означает, что наша программа передает управляющий другой запущенный модуль, который делает инъекции beans в наш код. (Каждый объект, который может быть введен, может быть подписан или рассмотрен как Bean.) Например, в Spring это делается путем создания и инициализации контейнера ApplicationContext, что делает это для нас. Мы просто в нашем коде создаем контекст и вызываем инициализацию beans. В этот момент инъекция была сделана автоматически.

4
ответ дан hariprasad 20 сент. '15 в 15:33
источник поделиться

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

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

4
ответ дан BERGUIGA Mohamed Amine 28 авг. '15 в 13:00
источник поделиться

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

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

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

3
ответ дан Waqas Ahmed 12 нояб. '13 в 8:19
источник поделиться

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

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

ВЗАИМОДЕЙСТВИЕ ЗАВИСИМОСТИ ПРОСТО СКРЫВАЕТ ДВУХ КЛАССОВ И В ТО ЖЕ ВРЕМЯ, ПОДДЕРЖИВАЯ ИХ ОТДЕЛЬНО.

3
ответ дан mohit sarsar 28 мая '14 в 12:08
источник поделиться

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

2
ответ дан kusnaditjung tjung 04 июня '16 в 2:34
источник поделиться

Инъекция зависимостей - это тип реализации принципа Инверсия управления, на основе которого построено Frameworks.

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

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

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

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

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

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

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

1
ответ дан Ciro Corvino 18 нояб. '16 в 1:01
источник поделиться

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

Подробнее см. введите ссылку здесь

0
ответ дан Hisham Javed 27 марта '17 в 13:16
источник поделиться
  • 1
  • 2

Другие вопросы по меткам