Что такое внедрение зависимостей? - PullRequest
2885 голосов
/ 25 сентября 2008

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

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

Ответы [ 34 ]

7 голосов
/ 12 ноября 2014

Я знаю, что ответов уже много, но я нашел это очень полезным: 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.

6 голосов
/ 02 апреля 2014

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

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

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

5 голосов
/ 18 мая 2013

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

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

4 голосов
/ 20 сентября 2015

Внедрение зависимостей (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) {

}

}

Все три класса могут быть скрыты для собственной реализации. Теперь мы можем использовать этот код для 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), что означает, что наша программа передает управление другому работающему модулю, который делает инъекции bean-компонентов в наш код. (Каждый объект, который может быть введен, может быть подписан или рассматриваться как Бин.) Например, в Spring это делается путем создания и инициализации контейнера ApplicationContext , который выполняет эту работу за нас. Мы просто в нашем коде создаем Context и вызываем инициализацию bean-компонентов. В этот момент инъекция была сделана автоматически.

4 голосов
/ 28 августа 2015

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

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

3 голосов
/ 12 ноября 2013

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

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

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

3 голосов
/ 21 сентября 2018

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

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

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

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

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

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

3 голосов
/ 28 мая 2014

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

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

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

3 голосов
/ 04 июня 2016

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

1 голос
/ 27 сентября 2018

Внедрение зависимостей - это практика, которая позволяет отделить независимые компоненты от некоторых из их зависимостей, следуя указаниям SOLID , которые гласят:

Принцип обращения зависимостей: нужно «зависеть от абстракций, не конкреции.

Лучшей реализацией внедрения зависимостей является шаблон проектирования Composition Root, поскольку он позволяет отделить компоненты от контейнера внедрения зависимостей.

Я рекомендую эту замечательную статью о корне композиции. http://blog.ploeh.dk/2011/07/28/CompositionRoot/ написанный Марком Симаном

вот основные моменты из этой статьи:

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

...

Только приложения должны иметь корни композиции. Библиотеки и рамки не должны.

...

На контейнер DI следует ссылаться только из корня композиции. Все остальные модули не должны иметь ссылки на контейнер.

Документация Di-Ninja, среды внедрения зависимостей, является очень хорошим примером, чтобы продемонстрировать, как работают принципы Composition Root и Dependency Injection. https://github.com/di-ninja/di-ninja Насколько мне известно, это единственный DiC в javascript, который реализует шаблон проектирования Composition-Root.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...