Что такое принцип инверсии зависимостей (DIP) в SOLID?

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

Ответ

Принцип инверсии зависимостей (Dependency Inversion Principle, DIP) — один из пяти принципов SOLID, который декларирует:

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

Цель: Уменьшить связанность между компонентами, повысить гибкость и тестируемость системы.

Пример нарушения DIP (жесткая зависимость):

// Конкретный класс нижнего уровня
class LightBulb {
    void turnOn() { System.out.println("Лампа включена"); }
}

// Класс верхнего уровня зависит от конкретной реализации
class Switch {
    private LightBulb bulb; // Зависимость от детали
    Switch(LightBulb bulb) { this.bulb = bulb; }
    void operate() { bulb.turnOn(); }
}

Пример с применением DIP:

// Абстракция (интерфейс)
interface Switchable {
    void turnOn();
}

// Конкретная реализация зависит от абстракции
class LightBulb implements Switchable {
    public void turnOn() { System.out.println("Лампа включена"); }
}
class Fan implements Switchable {
    public void turnOn() { System.out.println("Вентилятор запущен"); }
}

// Класс верхнего уровня зависит только от абстракции
class Switch {
    private Switchable device; // Зависимость от абстракции
    Switch(Switchable device) { this.device = device; }
    void operate() { device.turnOn(); }
}

// Использование
Switch lightSwitch = new Switch(new LightBulb());
Switch fanSwitch = new Switch(new Fan());

Преимущества:

  • Слабая связанность: Класс Switch не знает о конкретных устройствах.
  • Расширяемость: Легко добавить новое устройство, реализующее Switchable.
  • Тестируемость: Можно использовать мок-объекты в unit-тестах.
  • Гибкость: Поведение системы можно менять, подменяя реализации на уровне абстракций.