Поза рамками введення залежності, введення залежності (через інжектор конструктора або введення сетера) - це майже майже гра з нульовою сумою: ви зменшуєте зв’язок між об'єктом A і залежністю B, але тепер будь-який об'єкт, якому потрібен екземпляр A, повинен зараз також будують об’єкт B.
Ви трохи зменшили зв’язок між A і B, але зменшили інкапсуляцію A і збільшили зв'язок між A і будь-яким класом, який повинен побудувати екземпляр A, приєднавши їх також до залежності А.
Тож введення залежності (без рамки) приблизно так само шкідливо, як і корисно.
Однак додаткова вартість часто легко виправдана: якщо клієнтський код знає більше про те, як побудувати залежність, ніж сам об'єкт, то введення залежності дійсно знижує зв'язок; наприклад, Сканер не знає багато про те, як отримати або сконструювати вхідний потік для розбору вхідного сигналу або з якого джерела клієнтський код хоче проаналізувати вхід, тому введення конструктором вхідного потоку - очевидне рішення.
Тестування - ще одне виправдання для того, щоб мати можливість використовувати макетні залежності. Це повинно означати додавання додаткового конструктора, який використовується лише для тестування, який дозволяє вводити залежності: якщо ви замість цього замінюєте конструктори, щоб завжди вимагати введення залежностей, раптом, вам потрібно знати про залежності ваших залежностей, щоб побудувати свої прямі залежності, і ви не можете виконати жодної роботи.
Це може бути корисним, але ви, безумовно, повинні запитати себе про кожну залежність, чи варто користь тестування вартістю, і чи дійсно я хочу хотіти знущатися над цією залежністю під час тестування?
Коли додається рамка введення залежностей і побудова залежностей делегується не коду клієнта, а замість цього, аналіз витрат / вигод сильно змінюється.
У рамках залежності від введення залежності компроміси дещо відрізняються; те, що ви втрачаєте, вводячи залежність, - це можливість легко знати, на яку реалізацію ви покладаєтесь, і перекладати відповідальність за рішення, на яку залежність ви покладаєтесь, на якийсь автоматизований процес вирішення (наприклад, якщо нам потрібен @ Inject'ed Foo , повинно бути щось, що @Provides Foo і чиї введені залежності доступні), або якийсь файл конфігурації високого рівня, який прописує, який провайдер слід використовувати для кожного ресурсу, або якийсь гібрид із двох (наприклад, бути автоматизованим процесом розв’язання залежностей, які при необхідності можуть бути замінені, використовуючи файл конфігурації).
Як і у випадку з конструкторським введенням, я думаю, що перевага цього дійства знову-таки є дуже схожою на вартість цього: вам не потрібно знати, хто надає дані, на які ви покладаєтесь, і, якщо існує багато потенціалу Провайдери, вам не потрібно знати бажаний порядок перевірки провайдерів, переконайтеся, що кожне місцеположення, яке потребує перевірки даних, для всіх потенційних постачальників тощо, тому що все це обробляється на високому рівні шляхом введення залежності платформа.
Хоча я особисто не маю великого досвіду роботи з рамками DI, моє враження полягає в тому, що вони дають більше користі, ніж витрат, коли головний біль пошуку потрібного постачальника даних або послуги, який вам потрібен, має більшу вартість, ніж головний біль, коли щось не вдається, не одразу знати локально, який код надав погані дані, що спричинили пізню помилку у вашому коді.
У деяких випадках інші схеми, які неясні залежності (наприклад, сервісні локатори), вже були прийняті (і, можливо, також довели свою цінність), коли на сцені з'явилися рамки DI, а рамки DI були прийняті, оскільки вони пропонували певну конкурентну перевагу, наприклад, необхідність менший код котла або потенційно роблять менше, щоб закрити постачальника залежностей, коли виникає необхідність визначити, який постачальник послуг використовується.