В чем разница между Dependency Injection (DI) и Dependency Inversion Principle (DIP)?

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

Ответ

Dependency Inversion Principle (DIP) — это принцип проектирования (буква "D" в SOLID). Он состоит из двух правил:

  1. Модули верхнего уровня не должны зависеть от модулей нижнего уровня. Оба должны зависеть от абстракций (интерфейсов).
  2. Абстракции не должны зависеть от деталей. Детали (реализации) должны зависеть от абстракций.

Dependency Injection (DI) — это паттерн/техника реализации DIP, при котором зависимости объекта предоставляются ему извне ("внедряются"), а не создаются внутри класса.

Связь: DI — это практический способ соблюсти DIP.

Пример DIP + DI:

// Абстракция (интерфейс) - от нее зависят оба уровня
interface NotificationService {
    void send(String message);
}

// Деталь (нижний уровень) зависит от абстракции
class EmailService implements NotificationService {
    public void send(String message) { /* отправка email */ }
}

// Модуль верхнего уровня зависит от абстракции, а не от EmailService
class UserController {
    private final NotificationService service; // Зависимость от абстракции

    // Dependency Injection через конструктор
    public UserController(NotificationService service) {
        this.service = service; // Конкретная реализация внедряется извне
    }

    public void notifyUser() {
        service.send("Hello!");
    }
}

Итог: DIP — это "что" (цель проектирования), DI — это "как" (способ достижения).