Что такое внедрение зависимостей
Что проверяют
Отличаете ли вы паттерн от фреймворка и понимаете ли, что внедрение зависимостей это частный случай инверсии управления. На собеседовании за этим почти всегда идут вопросы про контейнер: как он строит граф, чем поле хуже конструктора, что делать с циклами.
Как отвечать
Определение короткое: зависимость приходит снаружи, класс объявляет, что ему нужно, и не решает, откуда это взять.
public class OrderService {
private final PaymentGateway gateway;
public OrderService(PaymentGateway gateway) {
this.gateway = gateway;
}
}Способов три: конструктор, сеттер, поле. Рабочий выбор это конструктор. Поле становится неизменяемым, объект после создания всегда валиден, зависимости видны в сигнатуре, а разросшийся список параметров честно сигналит, что класс взял на себя слишком много. Внедрение прямо в поле через рефлексию прячет зависимости и мешает создать объект в тесте обычным вызовом конструктора.
Контейнер вроде Spring ничего не меняет по сути, он автоматизирует: находит компоненты, строит граф, подставляет реализации, управляет областью жизни и порядком создания.
Сильный ответ заканчивается границей применимости. Абстракция нужна там, где реализация действительно меняется или где проходит граница с внешним миром. Интерфейс на каждый класс ради самого паттерна добавляет файлы и не добавляет гибкости.
Где спотыкаются
Называют внедрение зависимостей и инверсию управления синонимами. Инверсия шире: сервис-локатор тоже переворачивает управление, но зависимости в нём остаются скрытыми внутри класса, и тест приходится настраивать глобально.
Заводят интерфейс на каждую реализацию и гордятся слабой связанностью. Пока реализация одна и подменять её некем, это лишний слой, по которому неудобно навигировать и который ничего не изолирует.
Лечат циклическую зависимость ленивой подстановкой прокси вместо того, чтобы признать ошибку разбиения. Цикл в конструкторах почти всегда означает, что одна обязанность размазана по двум классам и просится третий.