Уже було розміщено декілька запитань із конкретними питаннями щодо введення залежності , наприклад, коли його використовувати та які рамки існують для цього. Однак,
Що таке ін'єкція в залежність і коли / чому слід або не слід застосовувати її?
Уже було розміщено декілька запитань із конкретними питаннями щодо введення залежності , наприклад, коли його використовувати та які рамки існують для цього. Однак,
Що таке ін'єкція в залежність і коли / чому слід або не слід застосовувати її?
Відповіді:
Залежність Ін'єкція - це передача залежності іншим об'єктам або рамкам (інжектор залежності).
Ін'єкційна залежність спрощує тестування. Ін'єкцію можна здійснити через конструктор .
SomeClass()
має свій конструктор наступним чином:
public SomeClass() {
myObject = Factory.getObject();
}
Проблема : Якщо myObject
пов'язані складні завдання, такі як доступ до диска або доступ до мережі, важко зробити перевірку блоку SomeClass()
. Програмісти повинні знущатися myObject
і можуть перехопити заводський виклик.
Альтернативне рішення :
myObject
як аргумент конструкторуpublic SomeClass (MyClass myObject) {
this.myObject = myObject;
}
myObject
можна пройти безпосередньо, що полегшує тестування.
Важко виділити компоненти в одиничному тестуванні без введення залежності.
У 2013 році, коли я писав цю відповідь, це була основна тема в блозі тестування Google . Для мене це залишається найбільшою перевагою, оскільки програмістам не завжди потрібна додаткова гнучкість у дизайні часу виконання (наприклад, для локатора обслуговування або подібних моделей). Програмістам часто потрібно ізолювати класи під час тестування.
Найкраще визначення, яке я знайшов поки що, - це Джеймс Шор :
"Ін'єкційна залежність" - це термін, що становить 25 доларів, для концепції 5 центів. [...] Введення залежності залежить від надання об'єкту змінних його примірників. [...].
Є стаття Мартіна Фаулера, яка також може виявитися корисною.
Введення залежності - це, головним чином, забезпечення об'єктів, необхідних об'єкту (його залежностей), а не їх конструювання. Це дуже корисна техніка для тестування, оскільки вона дозволяє знущатись або стримувати залежності.
Залежності можуть бути введені в об'єкти різними способами (наприклад, введення конструктора або введення сетера). Для цього навіть можна використовувати спеціалізовані системи введення залежності (наприклад, Spring), але вони, звичайно, не потрібні. Вам не потрібні ці рамки для введення залежності. Ігнорування та передача об'єктів (залежностей) явно є настільки ж доброю, як ін'єкція за рамками.
Я знайшов цей кумедний приклад з точки зору вільної зчеплення :
Будь-яка програма складається з безлічі об'єктів, які співпрацюють один з одним, щоб виконати якісь корисні речі. Традиційно кожен об'єкт несе відповідальність за отримання власних посилань на залежні об'єкти (залежності), з якими співпрацює. Це призводить до сильно поєднаних класів і важко перевіреного коду.
Наприклад, розглянемо а Car
об’єкт.
А Car
залежить від колес, двигуна, палива, акумулятора тощо. Традиційно ми визначаємо марку таких залежних об'єктів поряд з визначеннямCar
об'єкта.
Без впорскування залежностей (DI):
class Car{
private Wheel wh = new NepaliRubberWheel();
private Battery bt = new ExcideBattery();
//The rest
}
Тут Car
об’єкт відповідає за створення залежних об'єктів.
Що робити, якщо ми хочемо змінити тип його залежного об'єкта - скажімо Wheel
- після первинних NepaliRubberWheel()
проколів? Нам потрібно відтворити об'єкт "Автомобіль" з його новою залежністю ChineseRubberWheel()
, але це Car
може зробити тільки виробник.
Тоді, що робить Dependency Injection
для нас ...?
При використанні ін'єкцій залежності залежно від часу об'єктам задаються їх залежності , ніж час компіляції (час виготовлення автомобіля) . Так що тепер ми можемо змінювати Wheel
коли завгодно. Тут dependency
( wheel
) можна вводити Car
під час виконання.
Після використання ін'єкції залежності:
Тут ми ін'єкційні в залежність (колесо і акумулятор) під час виконання. Звідси термін: ін'єкційна залежність.
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;
}
}
Джерело: Розуміння ін'єкції залежності
new
в шина? Я не. Все, що мені потрібно зробити - це придбати у них (впорскувати через парам), встановити і ва-ла-ла! Отже, повертаючись до програмування, скажімо, проект C # повинен використовувати існуючу бібліотеку / клас, є два способи запуску / налагодження, 1-додати посилання на весь проект цього
new
це варіант, 2 варіант - передавати його як парам. Може бути не точним, але простим дурним легко зрозуміти.
Введення залежностей - це практика, коли об'єкти проектуються таким чином, щоб вони отримували екземпляри об'єктів з інших фрагментів коду, а не створювали їх внутрішньо. Це означає, що будь-який об’єкт, що реалізує необхідний об'єкт інтерфейс, може бути замінений без зміни коду, що спрощує тестування та покращує розв'язку.
Наприклад, розглянемо ці пункти:
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
що означає, що ви не можете "піддумати" aGroupMembershipService
для тестування або для використання стратегічного зразка в різних частинах вашої програми.
Завдяки введенню залежності, замість того, щоб миттєво встановлювати 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, тоді нам потрібно буде переписати автомобільний клас. І чим більше додаток, тим більше проблем і головного болю нам доведеться додати та використовувати новий тип двигуна.
Іншими словами, при такому підході, що наш клас автомобілів високого рівня залежить від нижнього рівня 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();
Тут ми в основному вводимо (передаємо) нашу залежність (екземпляр двигуна) конструктору автомобілів. Тож тепер у наших класах є слабке сполучення між об'єктами та їх залежностями, і ми можемо легко додавати нові типи двигунів, не змінюючи клас автомобілів.
Основна перевага ін'єкції залежності - це те, що класи більш вільно пов'язані, оскільки вони не мають жорстко кодованих залежностей. Це слідує принципу інверсії залежності, який був згаданий вище. Замість посилань на конкретні реалізації, класи запитують абстракції (зазвичай інтерфейси ), які надаються їм під час побудови класу.
Отже, врешті-решт, введення Dependency - це лише техніка досягнення слабкої зв'язку між об'єктами та їх залежностями. Замість того, щоб безпосередньо створювати залежності, необхідні класу для виконання своїх дій, залежності надаються класу (найчастіше) за допомогою конструкторської інжекції.
Крім того, коли у нас є багато залежностей, дуже корисно використовувати контейнери Інверсії управління (IoC), які ми можемо сказати, які інтерфейси слід відобразити, до яких конкретних реалізацій для всіх наших залежностей, і ми можемо це вирішити для нас, коли вони будуються наш об’єкт. Наприклад, ми могли б вказати в картографії для контейнера IoC, що залежність IEngine повинна бути віднесена до класу GasEngine, і коли ми запитаємо контейнер IoC для примірника нашого класу Car , він автоматично побудує наш клас автомобіля з залежністю GasEngine передав.
ОНОВЛЕННЯ: Нещодавно спостерігав за курсом EF Core від Джулі Лерман, а також сподобалось її коротке визначення про DI.
Ін'єкція залежності - це схема, яка дозволяє вашій програмі вводити об'єкти під час руху в класи, які їм потрібні, не примушуючи цих класів нести відповідальність за ці об'єкти. Це дозволяє вашому коду бути більш вільно пов'язаним, і Entity Framework Core підключається до цієї ж системи послуг.
Давайте уявимо, що ви хочете порибалити:
Без ін'єкцій залежностей потрібно про все подбати самостійно. Потрібно знайти човен, придбати вудку, шукати приманку і т. Д. Це, звичайно, можливо, але це покладає на вас велику відповідальність. У програмному відношенні це означає, що вам потрібно виконати пошук усіх цих речей.
З ін'єкцією залежностей хтось інший дбає про всю підготовку та надає необхідне вам обладнання. Ви отримаєте («уколу») човен, вудку та приманку - все готове до використання.
Це найпростіше пояснення про Dependency Injection і Dependency Injection Container я коли- небудь бачив:
Dependency Injection і Dependency Injection Контейнери різні речі:
Вам не потрібен контейнер для ін'єкції залежності. Однак контейнер може вам допомогти.
Чи не означає "введення залежності" просто використання параметризованих конструкторів та громадських сетерів?
У статті Джеймса Шора наведені наступні приклади для порівняння .
Конструктор без введення залежності:
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(); ... } }
new DatabaseThingie()
не створюється дійсний екземпляр myDatabase.
Щоб зробити концепцію вприскування залежності залежною від розуміння. Візьмемо приклад кнопки перемикання для включення (увімкнення / вимкнення) лампочки.
Перемикач повинен заздалегідь знати, до якої лампочки я підключений (жорстко кодова залежність). Тому,
Switch -> PermanentBulb // перемикач безпосередньо підключений до постійної лампочки, тестування неможливе легко
Switch(){
PermanentBulb = new Bulb();
PermanentBulb.Toggle();
}
Перемикач знає лише, що мені потрібно вмикати / вимикати залежно від того, яку лампочку передано мені. Тому,
Перемикач -> Лампа1 АБО Лампа2 АБО Нічна лампочка (введена залежність)
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) знімає відповідальність за безпосереднє створення та управління тривалістю життя інших об'єктів, від яких залежить наш клас інтересів (споживчий клас) (у розумінні UML ). Ці екземпляри замість цього передаються до нашого споживчого класу, як правило, в якості параметрів конструктора або через встановлення властивостей (управління об'єктом залежності та перехід до споживчого класу зазвичай виконується контейнером інверсії управління (IoC) , але це інша тема) .
DI, DIP і твердий
В Зокрема, в парадигмі Роберта C Мартіна ТВЕРДИХ принципів об'єктно - орієнтованого дизайну , DI
є одним з можливих реалізацій Принцип інверсії залежностей (DIP) . DIP є D
в SOLID
мантре - інші реалізації DIP включають Service Locator, і патерни Plugin.
Метою 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)?
Розв'язка залежностей між класами таким чином дозволяє легко замінити ці класи залежностей іншими реалізаціями, які також відповідають умовам абстракції (наприклад, залежність може бути переключена з іншою реалізацією того ж інтерфейсу). Крім того, як уже згадувалося, можливо , найбільш поширеною причиною для класів роз'єднати з допомогою DIP, щоб дозволити споживаючи клас для тестування в ізоляції, так як ці ж залежностей тепер можуть бути загасив і / або знущалися.
Одним із наслідків DI є те, що управління життєвими прикладами об'єктів залежності більше не контролюється споживчим класом, оскільки об'єкт залежності тепер передається в клас споживання (через введення конструктора або сетера).
Це можна переглянути по-різному:
Create
завод на заводі у міру необхідності та розпоряджатися цими екземплярами після їх завершення.Коли використовувати DI?
MyDepClass
безпечна нитка - що робити, якщо ми зробимо це однократним і введемо той самий екземпляр у всіх споживачів?)Приклад
Ось проста реалізація C #. Зважаючи на нижчий клас споживання:
public class MyLogger
{
public void LogRecord(string somethingToLog)
{
Console.WriteLine("{0:HH:mm:ss} - {1}", DateTime.Now, somethingToLog);
}
}
Хоча, здавалося б, нешкідливий, він має дві static
залежності від двох інших класів, System.DateTime
і System.Console
які не тільки обмежують параметри виходу журналу (реєстрація на консолі буде марною, якщо ніхто не дивиться), але ще гірше, важко автоматично перевірити, враховуючи залежність від недетермінований системний годинник.
Однак ми можемо застосувати DIP
до цього класу, усуваючи занепокоєння тимчасовими позначками як залежністю і зв'язуючи MyLogger
лише простий інтерфейс:
public interface IClock
{
DateTime Now { get; }
}
Ми можемо також послабити залежність від Console
абстракції, наприклад, як TextWriter
. Залежність впорскування зазвичай реалізується як constructor
ін'єкція (передача абстракції залежності, як параметр конструктору споживчого класу), або 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
екземпляр" )IDisposable
і вони візьмуть на себе відповідальність Disposing
залежно від налаштованого управління життям.Як правило, після конфігурування / завантаження завантажених контейнерів IoC вони працюють безшовно на задньому плані, що дозволяє кодеру зосередити увагу на коді, а не турбуватися про залежності.
Ключ до дружнього коду - уникати статичного з’єднання класів, а також не використовувати новий () для створення залежностей
Згідно з наведеним вище прикладом, розв'язка залежностей вимагає певних зусиль із проектування, і для розробника існує зміна парадигми, необхідна для того, щоб зруйнувати звичку new
безпосередньо використовувати залежності, а замість цього довіряти контейнеру для управління залежностями.
Але переваг багато, особливо в можливості ретельно перевірити свій клас інтересів.
Примітка : Створення / відображення / проекція (через new ..()
) POCO / POJO / Серіалізація DTO / Entity Graphs / Anonymous JSON projections та ін. - тобто класи "Дані", які використовуються або повертаються з методів, не розглядаються як залежності (у Сенс UML) і не підлягає DI. Використовувати new
для проектування це просто чудово.
Вся суть введення залежності (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
Залежність тільки що була введена в залежний сценарій.
Ви могли ввести залежність, яка реалізується archive_files
за допомогою tar
або xz
.
Якщо dependent.sh
скрипт безпосередньо використовував залежності, підхід буде називатися пошуком залежності (що протилежно введенню залежності ):
#!/bin/sh
# Dependent
# dependency look-up
source ./archive_files_zip.sh
touch "one.txt" "two.txt"
archive_files "one.txt" "two.txt"
Тепер проблема полягає в тому, що залежний "компонент" повинен виконувати ініціалізацію сам.
Вихідний код "компонента" не є ні чистим, ні стабільним оскільки для кожного зміни ініціалізації залежностей необхідний новий випуск і для файлу вихідного коду "компонентів".
DI не так сильно підкреслюється та популяризується, як у рамках Java.
Але це загальний підхід, щоб розділити проблеми:
Використання конфігурації лише з пошуком залежності не допомагає, оскільки кількість параметрів конфігурації може змінюватися в залежності від залежності (наприклад, новий тип аутентифікації), а також кількість підтримуваних типів залежностей (наприклад, новий тип бази даних).
Усі вищезазначені відповіді хороші, моя мета - пояснити концепцію простим способом, щоб кожен, хто не знає програмування, також міг зрозуміти концепцію
Вприскування залежностей - одна із схем розробки, яка допомагає нам створювати складніші системи простішим способом.
Ми можемо побачити найрізноманітніші сфери застосування цієї моделі в нашому повсякденному житті. Деякі приклади - магнітофон, VCD, CD-диск тощо.
Наведене вище зображення - це зображення портативного магнітофона котушки до котушки, середина 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();
}
Ви також можете прочитати
Ін'єкційна залежність (DI) означає роз'єднання об'єктів, які залежать один від одного. Скажімо, об’єкт A залежить від Об'єкта B, тому ідея полягає в тому, щоб від'єднати ці об'єкти один від одного. Нам не потрібно сильно кодувати об'єкт, використовуючи нове ключове слово, а не ділити залежність для об'єктів під час виконання, незважаючи на час компіляції. Якщо говорити про
Нам не потрібно сильно кодувати об'єкт за допомогою нового ключового слова, а не визначати залежність bean у файлі конфігурації. Пружинний контейнер буде відповідати за підключення всіх.
МОК - це загальне поняття, і воно може виражатися різними способами, а введення залежностей - один конкретний приклад МОК.
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>
DI на основі сеттера виконується методами встановлення контейнерів на вашій квасолі після виклику конструктора без аргументів або статичного фабричного методу без аргументів для інстанціювання вашого квасолі.
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 наближає вас до принципу єдиної відповідальності (SR), як і surgeon who can concentrate on surgery
.
Коли використовувати DI: я б рекомендував використовувати DI майже у всіх виробничих проектах (малих / великих), особливо у постійно мінливих бізнес-середовищах :)
Чому: Тому що ви хочете, щоб ваш код був легко перевіряється, макерувався і т. Д., Щоб ви могли швидко протестувати свої зміни та перенести їх на ринок. Крім того, чому б вам не було, коли у вас є безліч дивовижних безкоштовних інструментів / рамок, які допоможуть вам у вашій подорожі до кодової бази, де ви маєте більше контролю.
Наприклад, у нас є 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) Використовуйте бібліотеку: для кінця Android2
Переваги
Service
, вам потрібно змінити його лише у класі інжекторConstructor Injection
, дивлячись на конструктор Client
, ви побачите, скільки залежить Client
класНедоліки
Constructor Injection
, Service
об’єкт створюється при Client
створенні, колись ми використовуємо функцію в Client
класі без використання, Service
так створене Service
використання марноhttps://en.wikipedia.org/wiki/Dependency_injection
Залежність - це об'єкт, який можна використовувати (
Service
)
Ін'єкція - це передача залежності (Service
) на залежний об'єкт (Client
), який би використовував її
Це означає, що об'єкти повинні мати лише стільки залежностей, скільки потрібно для виконання своєї роботи, а залежностей має бути мало. Крім того, залежність об'єкта повинна бути, коли це можливо, від інтерфейсів, а не від "конкретних" об'єктів. (Конкретним об'єктом є будь-який об’єкт, створений за допомогою ключового слова new.) Вільний зв'язок сприяє більшій повторній експлуатації, більш легкій ремонтопридатності та дозволяє легко надавати «глузуючі» об’єкти замість дорогих послуг.
"Впорскування впорскування" (DI) також відоме як "Інверсія управління" (IoC), може використовуватися як техніка для заохочення цієї нещільної зв'язку.
Існує два основні підходи до впровадження DI:
Це техніка передачі залежностей об'єктів його конструктору.
Зауважте, що конструктор приймає інтерфейс, а не конкретний об'єкт. Також зауважте, що виняток видається, якщо параметр orderDao є нульовим. Це підкреслює важливість отримання дійсної залежності. На мою думку, конструкторська ін'єкція є кращим механізмом надання об'єкту його залежностей. Розробнику зрозуміло, посилаючись на об'єкт, які залежності потрібно надати об'єкту "Особа" для належного виконання.
Але розглянемо наступний приклад… Припустимо, у вас клас з десятьма методами, які не мають залежностей, але ви додаєте новий метод, який має залежність від IDAO. Ви можете змінити конструктор на використання конструкторської ін'єкції, але це може змусити вас змінити всі виклики конструктора в усьому місці. Крім того, ви можете просто додати новий конструктор, який приймає залежність, але тоді як розробник легко знає, коли використовувати один конструктор над іншим. Нарешті, якщо залежність створити дуже дорого, чому її слід створювати та передавати конструктору, коли вона може використовуватися лише рідко? "Ін'єкція сетера" - ще одна техніка DI, яку можна використовувати в таких ситуаціях.
Інжекція встановлення не змушує передавати залежності конструктору. Натомість залежності встановлюються на загальнодоступні властивості, що піддаються необхідному об'єкту. Як випливало раніше, до основних мотиваторів для цього належать:
Ось приклад того, як виглядатиме наведений вище код:
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;
Я думаю, оскільки всі написали для DI, дозвольте мені задати кілька питань ..
Це ґрунтується на опублікованій відповіді @Adam N.
Чому PersonService більше не має турбуватися про GroupMembershipService? Ви щойно згадали GroupMembership має багато речей (об'єктів / властивостей), від яких залежить. Якщо в PService потрібна GMService, ви матимете її як властивість. Ви можете знущатися над цим незалежно від того, ввели ви його чи ні. Єдиний раз, коли я хотів би, щоб його вводили, якщо в GMService були більш конкретні класи дітей, про які ви не знали б до часу виконання. Тоді ви хочете вставити підклас. Або якщо ви хочете використовувати це як однотонний або прототип. Якщо чесно, у конфігураційному файлі є все жорстке кодування, що стосується того, який підклас для типу (інтерфейсу) він збирається вводити під час компіляції.
EDIT
Приємний коментар Жозе Марії Арранц щодо DI
DI збільшує згуртованість, усуваючи будь-яку потребу визначити напрямок залежності і написати будь-який клей-код.
Помилковий. Напрямок залежностей у формі XML або як анотації, ваші залежності записуються як код XML та анотації. XML та примітки є вихідним кодом.
DI знижує з'єднання, роблячи всі ваші компоненти модульними (тобто замінюваними) і мають чітко визначені інтерфейси один до одного.
Помилковий. Вам не потрібна рамка DI для побудови модульного коду на основі інтерфейсів.
Про замінний: за допомогою дуже простого архіву .properties та Class.forName ви можете визначити, які класи можуть змінюватися. Якщо будь-який клас вашого коду можна змінити, Java не для вас, використовуйте мову сценаріїв. До речі: анотації неможливо змінити без перекомпіляції.
На мою думку, є одна єдина причина каркасів: зменшення плит котла. За допомогою добре виконаної фабричної системи ви можете зробити те ж саме, більш контрольоване та більш передбачуване, як і ваш бажаний фреймворк DI, рамки DI обіцяють зменшення коду (XML та анотації теж вихідний код). Проблема полягає в тому, що це зменшення плит котла реально в дуже простих випадках (один екземпляр на клас і подібне), іноді в реальному світі вибір відповідного об’єкта обслуговування не такий простий, як зіставлення класу на однотонний об'єкт.
Популярні відповіді не допомагають, оскільки вони визначають введення залежності таким чином, який не є корисним. Погодимось, що під "залежністю" ми маємо на увазі деякий раніше існуючий інший об'єкт, який потрібен нашому об'єкту X. Але ми не кажемо, що робимо "ін'єкцію залежності", коли говоримо
$foo = Foo->new($bar);
Ми просто називаємо ці параметри передачі в конструктор. Ми робимо це регулярно з тих пір, як були винайдені конструктори.
"Введення залежності" вважається типом "інверсії управління", що означає, що якась логіка виймається з абонента. Це не той випадок, коли абонент передає параметри, тому, якби це було DI, DI не означало б інверсію управління.
DI означає, що між абонентом та конструктором є проміжний рівень, який управляє залежностями. Makefile - простий приклад введення залежності. "Зателефонуючий" - це людина, яка вводить "make bar" у командному рядку, а "конструктор" - компілятор. Makefile визначає, що смуга залежить від foo, і це робить a
gcc -c foo.cpp; gcc -c bar.cpp
перш ніж робити а
gcc foo.o bar.o -o bar
Людині, яка набирає "зробити бар", не потрібно знати, що бар залежить від foo. Залежність вводили між "make bar" та gcc.
Основне призначення проміжного рівня - це не просто передати залежності конструктору залежностей, а перерахувати всі залежності лише в одному місці та приховати їх від кодера (не змусити кодер їх надати).
Зазвичай проміжний рівень забезпечує заводи для побудованих об'єктів, які повинні забезпечувати роль, яку повинен задовольняти кожен запитуваний тип об'єкта. Це тому, що, маючи проміжний рівень, який приховує деталі будівництва, ви вже зазнали штрафу за абстракцію, який накладають фабрики, тож ви можете також використовувати фабрики.
Ін'єкційна залежність означає спосіб (насправді будь-який спосіб ) для однієї частини коду (наприклад, класу) отримати доступ до залежностей (інших частин коду, наприклад, інших класів, це залежить) модульним способом без їх жорсткого кодування (так вони можуть змінюватися або змінюватися вільно, або навіть завантажуватися в інший час, якщо потрібно)
(і 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
. Хоча MyDao
клас все ще залежить від цих чотирьох значень, він більше не задовольняє цих залежностей. Їх надає будь-який клас, який створює MyDao
екземпляр.
Введення залежності - це одне можливе рішення того, що в цілому можна назвати вимогою "Обмеження залежності". Обфузація залежності - це метод виведення «очевидного» характеру з процесу забезпечення залежності класу, який цього вимагає, і, таким чином, обдумує, певним чином, надання зазначеної залежності вказаному класу. Це не обов’язково погано. Насправді, оскаржуючи спосіб, яким надається залежність класу, то щось поза класом відповідає за створення залежності, що означає, що в різних сценаріях до класу може бути поставлена різна реалізація залежності, не вносячи жодних змін до класу. Це чудово підходить для перемикання між режимами виробництва та тестування (наприклад, використання залежної від служби "макету").
На жаль, погана частина полягає в тому, що деякі люди припускають, що вам потрібна спеціалізована структура для затухання залежності і що ви якимось "меншим" програмістом, якщо ви вирішите не використовувати певну структуру для цього. Інший, надзвичайно тривожний міф, в який вважають багато людей, полягає в тому, що введення залежності є єдиним способом досягнення затухання залежності. Це демонстративно і історично, і очевидно, що на 100% помиляється, але у вас виникнуть проблеми переконати деяких людей, що існують альтернативи ін'єкції залежності для ваших потреб обфузації залежності.
Програмісти роками розуміли вимогу обфузації залежності, і багато альтернативних рішень складалися як до, так і після того, як було задумано введення залежності. Існують фабричні зразки, але також існує багато варіантів використання ThreadLocal, де не потрібна ін'єкція певному екземпляру - залежність ефективно вводиться в нитку, що має перевагу надання об’єкту доступним (за допомогою зручних статичних методів отримання) для будь-якогоклас, який вимагає цього, не потрібно додавати анотації до класів, які вимагають цього, і встановлювати хитромудрий XML 'клей', щоб це сталося. Коли ваші залежності потрібні для збереження (JPA / JDO чи будь-що інше), це дозволяє досягти "прозорої стійкості" набагато простіше і за допомогою доменних моделей та класів бізнес-моделей, складених виключно з POJO (тобто не має конкретних рамок / зафіксованих в анотаціях).
З книги « Добре заземлений Java Developer: Vital техніка Java 7 та програмування поліглотів
DI - це особлива форма IoC, згідно з якою процес пошуку ваших залежностей знаходиться під безпосереднім контролем вашого виконуваного в даний час коду.
Перш ніж перейти до технічного опису, спочатку візуалізуйте його на прикладі реального життя, оскільки ви знайдете багато технічних речей, щоб вивчити ін'єкцію залежності, але максимальний час, як я, не можу отримати основної концепції цього.
На першому знімку припустімо, що у вас є фабрика автомобілів з великою кількістю об'єднань. Автомобіль фактично вбудований у складальний блок, але йому потрібні двигун , сидіння та колеса . Тож монтажний блок залежить від усіх цих агрегатів, і вони залежать від заводу.
Ви можете відчути, що зараз виконувати всі завдання на цій фабриці занадто складно, оскільки поряд з основним завданням (Збирання автомобіля в складальній одиниці) вам потрібно також зосередитися на інших підрозділах . Зараз утримувати це дуже дорого, а заводська будівля величезна, тому вона займе ваші зайві гроші на оренду.
А тепер подивіться на другу картинку. Якщо ви знайдете компанії-постачальники, які забезпечать вам колесо , сидіння та двигун дешевше, ніж ваші витрати на самовиробництво, то тепер вам не потрібно робити їх на вашому заводі. Тепер ви можете взяти на оренду меншу будівлю лише для монтажної одиниці, що зменшить завдання з обслуговування та зменшить додаткові витрати на оренду. Тепер ви також можете зосередитись лише на своєму головному завданні (складання автомобіля).
Тепер ми можемо сказати, що всі залежності для складання автомобіля нагнітаються на заводі від постачальників . Це приклад реальної ін'єкції в реальному житті (DI) .
Тепер у технічному слові введення залежності - це техніка, за допомогою якої один об'єкт (або статичний метод) забезпечує залежності іншого об'єкта. Отже, перенесення завдання створення об’єкта комусь іншому та безпосередньо використання залежності називається ін'єкцією залежності.
Це допоможе вам зараз навчитися DI з якимсь технічним словом. Це покаже, коли використовувати DI, а коли не слід .
від Book Apress.Spring.Persistence.with.Hibernate.Oct.2010
Мета введення залежності - від'єднати роботу з вирішення зовнішніх компонентів програмного забезпечення від бізнес-логіки вашого додатка. Без введення залежностей деталі того, як доступ до компонентів, необхідних службам, може заплутатися в коді компонента. Це не тільки збільшує потенціал помилок, додає розширення коду та збільшує складність технічного обслуговування; він з'єднує компоненти більш тісно, що ускладнює модифікацію залежностей при рефакторингу чи тестуванні.
Dependency Injection (DI) - це одна з шаблонів дизайну, яка використовує основну особливість OOP - взаємозв'язок одного об'єкта з іншим об'єктом. У той час як спадкування успадковує один об'єкт, щоб зробити більш складним і конкретизованим інший об'єкт, зв’язок або асоціація просто створює вказівник на інший об'єкт з одного об’єкта за допомогою атрибута. Потужність DI поєднується з іншими особливостями OOP, як інтерфейси та прихований код. Припустимо, у нас у бібліотеці є клієнт (абонент), який для простоти може позичити лише одну книгу.
Інтерфейс книги:
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 так тісно пов'язаний з Інверсією управління (IoC), що означає, що наша програма передає управління іншому запущеному модулю, який робить ін'єкції бобів до нашого коду. (Кожен об'єкт, який може бути введений, може бути підписаний або розглянутий як Bean.) Наприклад, навесні це робиться шляхом створення та ініціалізації ApplicationContextконтейнер, який робить це для нас. Ми просто в своєму коді створюємо контекст і викликаємо ініціалізацію бобів. У цей момент ін'єкцію робили автоматично.
Ін'єкційна залежність для 5-річних дітей.
Коли ви підете і дістанете речі з холодильника для себе, ви можете викликати проблеми. Ви можете залишити двері відкритими, ви можете отримати щось, чого мама чи тато не хочуть. Ви можете навіть шукати те, чого ми навіть не маємо або термін дії якого закінчився.
Що ви повинні робити, це заявити про необхідність: "Мені потрібно щось випити за обідом", і тоді ми переконаємося, що у вас є щось, коли ви сідете їсти.
З Крістофера Норінга, книга Пабло Ділмана "Навчання кутовим - друге видання":
«Оскільки наші додатки ростуть і розвивається, кожен з наших кодових сутностей буде внутрішньо вимагати примірників інших об'єктів , які є більш відомими як залежності в світі програмної інженерії. Дія проходження таких залежностей залежного клієнта відомо як ін'єкції , і це також передбачає участь іншого суб'єкта коду, який називається інжектором . Інжектор візьме на себе відповідальність за інстанціювання та завантаження необхідних залежностейтому вони готові до використання з того моменту, коли вони успішно вводяться у клієнта. Це дуже важливо , тому що клієнт не знає нічого про те , як створити екземпляр своїх залежностей і знає тільки з інтерфейсу вони реалізують для того , щоб використовувати їх «.
Від: Антон Мойсеєв. книга "Кутова розробка з машинописом, друге видання.":
"Коротше кажучи, DI допомагає вам писати код у зв'язаному вигляді і робить ваш код більш перевіреним та багаторазовим ".
Простими словами, введення залежності (DI) - це спосіб усунення залежностей або тісної зв'язку між різними об'єктами. Ін'єкційна залежність дає згуртовану поведінку кожному об'єкту.
DI - це реалізація директора МОК Spring, який говорить: "Не дзвоніть нам, ми зателефонуємо вам". Використовуючи програміст ін'єкцій залежностей, не потрібно створювати об'єкт за допомогою нового ключового слова.
Об'єкти один раз завантажуються у контейнер Spring, а потім ми використовуємо їх повторно, коли нам це потрібно, отримуючи ці об'єкти з Spring контейнера методом getBean (String beanName).
Ін'єкція залежностей є основою концепції, пов’язаної з Spring Framework. Якщо створення рамки будь-якого проекту весна може виконувати життєво важливу роль, і тут ін'єкція залежності входить у глечик.
Насправді, припустимо, у java ви створили два різні класи, як клас A і клас B, і яку б функцію ви не мали в класі B, яку ви хочете використовувати в класі A, тож у цей час можна використовувати ін'єкцію залежності. де ви можете створити об'єкт одного класу в іншому, таким же чином ви можете вставити весь клас в інший клас, щоб зробити його доступним. цим способом залежність можна подолати.
ІНДЕКЦІЯ ВІДПОВІДЬНОСТІ ПРОСТО СКЛЮЧЕННЯ ДВОХ КЛАСІВ І НА ТОЖИЙ ЧАС ЗДІЙСНЯЄТЬСЯ ЇХ СЕПАРАТ.