Что означает инъекция в инъекциях конструкторов и инъекций зависимостей

Я читал об инъекции зависимостей. Затем наступает

  • инъекция конструктора,
  • Геттер Инъекция
  • Инъекция сеттера
  • Инъекция интерфейса

Чем они отличаются от внедрения зависимостей или все они одинаковы? Что здесь означает Injection? Просто дать требуемый объект/параметр классу? Подобно внедрению конструкции, означает передачу требуемого параметра в качестве параметра конструктора? или я что-то упускаю?


person Shobi    schedule 16.02.2018    source источник
comment
Вы понимаете слово инъекция?   -  person matt    schedule 16.02.2018
comment
что-то извне вводится внутрь объекта. решение для слабой связи и сделать связывание зависимостей bean-компонентов управляемым фреймворком. так что в целом ваши предложения верны.   -  person snap    schedule 16.02.2018


Ответы (3)


  • Внедрение зависимостей — это действие по предоставлению классу его зависимостей путем предоставления их третьей стороной.

  • внедрение в конструктор – наиболее распространенная форма внедрения зависимостей. . Внедрение конструктора – это действие по статическому определению списка необходимых зависимостей путем указания их в качестве параметров конструктора класса.

  • Внедрение сеттера (также известное как Внедрение свойства) и Внедрение метода (при этом Внедрение интерфейса является специализация Method Injection) — это альтернативные формы предоставления (или «внедрения») зависимости в потребляющий класс.

  • Насколько мне известно, Getter Injection не существует. Getter может только извлекать значения, но не устанавливать их, что является требованием для внедрения зависимостей.

Таким образом, внедрение конструктора, внедрение сеттера и внедрение интерфейса являются формами внедрения зависимостей. . Внедрение конструктора — это наиболее распространенная форма внедрения зависимостей, которая заставляет класс создаваться со всеми необходимыми зависимостями. Поэтому внедрение конструктора должно быть вашей предпочтительной формой внедрения зависимостей. Однако есть случаи, когда внедрение метода или внедрение свойства также имеет смысл. В книге Dependency Injection Principles, Practices, and Patterns (автор Марк Симанн и я) подробно рассматривается эти формы DI (особенно глава 4 ).

person Steven    schedule 17.02.2018
comment
Очень хороший ответ - person Shobi; 17.02.2018

Три формы внедрения зависимостей: конструктор, сеттер, интерфейс [и четвертая, контекстная]. Я никогда не слышал о Getter Injection, поэтому не буду упоминать его. Внедрение — это просто как объект или компонент связан с другим объектом или компонентом, обычно с классом. Без внедрения зависимостей компоненты считаются «сильно связанными», если они имеют какую-либо форму связи. Например, рассмотрим этот класс (написанный на Java), который не использует внедрение зависимостей:

public class Salesman implements Worker {
     private Car itemForSale;
     public Salesman() {
          itemForSale = new Car("BMW");
     }
     public void printItemSold() {
          System.out.println("The salesman sold a " + itemForSale.name() 
          + " at price $"+itemForSale.price());
     }
}

Здесь класс Salesman тесно связан с классом Car. Учтите, что продавец может фактически также продавать детали, инструменты и услуги. Однако поле itemForSale является объектом Car, и конструктор по умолчанию здесь устанавливает для itemForSale объект Car. У нас была бы более слабая связь, если бы мы изменили конструктор на public Salesman(String carName, double carPrice), но, тем не менее, это не разделило бы Salesman и Cars — объект Saleman по-прежнему «зависит» от объекта Car в своей функциональности.

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

public class Salesman implements Worker {
     private Item itemForSale;
     public Salesman(Item item){
          itemForSale = item;
     }
     public void printItemSold(){
          System.out.println("salesman sold a " + itemForSale");
     }
}

Теперь мы можем написать в другом классе:

Item car = new Car("Jeep", 8900); // the Car class implements the Item item class/interface
Salesman salesman = new Salesman(car);
salesman.printItemSold();

Item part = new Part("tires", 67.99); // the Part class also implements the Item class/interface
Salesman salesman = new Salesman(part);
salesman.printItemSold();

... and so on.

Ключевым преимуществом здесь, которое может быть трудно увидеть в таком простом случае, является то, что объект Salesman никоим образом не зависит от класса Car. Чтобы охватить все различные типы продаваемых объектов, нам не нужны поля «Автомобиль», «Запчасти», «Сервис» и т. д., а также нам не нужно реализовывать такую ​​логику, как

if (car != null) 
     printItemSold(car) 
else if (part != null)
     printItemSold(part)
...

Скорее, все, что нам нужно сделать, это просто предоставить (или внедрить) Item, который продавец продал объекту Salesman.

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

public class Salesman implements Worker {
     private Item itemForSale;
     public Salesman() { }
     public void setItem(Item item){
          this.itemForSale = item;
     }
     ...
} 

Теперь мы можем сделать:

Salesman salesman = new Salesman();
salesman.setItem(new Car("Toyota", 23938.23);
salesman.print();
salesman.setItem(new Service("oil change", 17.78);
salesman.print();

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

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

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

Вы можете установить это как поле в своем классе, настроить его, установить или открыть, начать и завершить транзакции и убедиться, что оно закрыто к моменту завершения вашей программы, и все это самостоятельно. Однако было бы неплохо, если бы все, что вам нужно было сделать, это просто объявить, что вам нужен объект подключения, а затем управлять этим подключением за вас. Соединение открывается только тогда, когда оно необходимо, когда вы вызываете connection.save(data), транзакция автоматически начинается и фиксируется, а когда вы завершаете свою программу, соединение автоматически закрывается несмотря ни на что, даже если у вас есть исключение или ошибка. В Java Spring, например, это будет просто включать аннотацию @Component или @Bean в ваш класс Connection, а затем объявить @Autowired Connection connection // the Connection will even be constructed for you в любом классе, использующем соединение.

Это стало большой проблемой в мире программирования. Чтобы понять почему, предположим, что у вас есть соединение, которое принимает объект Driver, такой как MySQLDriver, MSSQLDriver или PostgresDriver. Конечно, каждый из этих драйверов реализуется по-разному и требует уникального набора конфигураций. Но с объектом управляемого соединения, который вы запрашиваете в объявляющем классе, все, что вам нужно сделать при переходе от одной базы данных к другой, — это использовать форму внедрения конструктора или установщика: Connection conn = new Connection(MSSQLDriver); или @Autowired Connection conn; conn.setDriver(PostgresDriver); Это может сэкономить часы времени и устранить необходимо изучить сложный «шаблонный» код, поскольку все, что вам нужно сделать, это внести одно изменение в наше поле, и ваш объект будет управляться соответствующим образом.

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

person Christian Meyer    schedule 22.04.2019

Затем в Dagger 2 есть конструктор @Inject, и это нечто другое, и младшие разработчики могут принять за него это. Это выглядит так:

ListAdapter @Inject constructor() : RecyclerView.Adapter<ListViewHolder>() {
//code
}

Выше это Kotlin, на Java это выглядит так:

class ListAdapter extends RecyclerView.Adapter<ListViewHolder>() {

@Inject
public ListAdapter(Context context) {

}

}

Это особенность Dagger 2, которая позволяет вам генерировать @Provides без фактического написания @Provides функций/пустот в модулях.

Аннотируя конструктор с помощью inject, вы также сообщаете dagger, что существует класс с именем X, и вам нужен контекст для его создания. В основном это то же самое, что добавить его в свой модуль.

person Stanislav Kinzl    schedule 12.02.2019