Что такое Dependency Injection (DI) и зачем он нужен?

«Что такое Dependency Injection (DI) и зачем он нужен?» — вопрос из категории Spring, который задают на 10% собеседований Java Разработчик. Ниже — развёрнутый ответ с разбором ключевых моментов.

Ответ

Dependency Injection (DI, Внедрение зависимостей) — это паттерн проектирования, при котором зависимости объекта (сервисы, которые он использует) предоставляются ему извне, а не создаются внутри самого объекта.

Цель и преимущества:

  • Снижение связанности (Low Coupling): Классы не зависят от конкретных реализаций своих зависимостей, а только от их абстракций (интерфейсов).
  • Упрощение тестирования: Зависимости легко подменить mock- или stub-объектами в unit-тестах.
  • Повышение гибкости и поддерживаемости: Изменение реализации зависимости требует правки только в конфигурации, а не в каждом использующем её классе.
  • Централизованное управление: Жизненный цикл и конфигурация зависимостей управляются контейнером (например, Spring IoC).

Способы внедрения:

  1. Через конструктор (предпочтительный):
    public class OrderService {
        private final PaymentProcessor processor;
        // Зависимость инжектируется при создании
        public OrderService(PaymentProcessor processor) {
            this.processor = processor; // Внедрение
        }
    }
  2. Через сеттер:
    public class OrderService {
        private PaymentProcessor processor;
        @Autowired // Аннотация Spring
        public void setProcessor(PaymentProcessor processor) {
            this.processor = processor;
        }
    }
  3. Через поле (менее предпочтительно из-за сложности тестирования без контейнера):
    public class OrderService {
        @Autowired
        private PaymentProcessor processor;
    }

    Без DI (проблемный код):

    public class OrderService {
    private PaymentProcessor processor = new PayPalProcessor(); // Жёсткая привязка
    // Тестировать или менять реализацию сложно.
    }

    DI является ключевым принципом, лежащим в основе Inversion of Control (IoC) контейнеров, таких как Spring Framework.