digital-garden/dev/architecture/Dependency Inversion Principle.md
Struchkov Mark 6d903d4988
Some checks failed
continuous-integration/drone/push Build is failing
Обновление
2024-11-24 20:43:38 +03:00

4.8 KiB
Raw Blame History

aliases tags date zero-link parents linked
DIP
Принцип инверсии зависимостей
maturity/🌱
2024-09-27
../../meta/zero/00 Архитектура ПО
SOLID

Принцип инверсии зависимостей (Dependency Inversion Principle, DIP) гласит: высокоуровневые модули не должны зависеть от низкоуровневых модулей. Оба должны зависеть от абстракций. Это означает, что вместо использования конкретных реализаций, классы должны работать с абстракциями — интерфейсами или абстрактными классами. DIP делает код более гибким, модульным и легко расширяемым.

Как соблюдать DIP

  1. Работайте с абстракциями: Замените зависимости на интерфейсы или абстрактные классы.
  2. Инвертируйте зависимости: Используйте внедрение зависимостей (Dependency Injection) через конструктор, сеттер или контейнеры.
  3. Минимизируйте жёсткую связанность: Высокоуровневые модули должны оставаться независимыми от деталей реализации низкоуровневых модулей.

Преимущества соблюдения DIP

  1. Гибкость: Замена низкоуровневых модулей (реализаций) не требует изменения высокоуровневых модулей.
  2. Улучшенная тестируемость: Высокоуровневые модули можно тестировать с помощью моков или заглушек, так как они зависят от абстракций.
  3. Снижение связанности: Высокоуровневый код становится независимым от деталей реализации.
  4. Расширяемость: Новые реализации интерфейсов можно добавлять без изменений в существующем коде.

Пример нарушения DIP

Рассмотрим пример с выключателем, который управляет лампой:

public class Lamp {
    public void turnOn() {
        // Лампа включена
    }
}

public class Switch {
    private Lamp lamp;

    public Switch(Lamp lamp) {
        this.lamp = lamp;
    }

    public void toggle() {
        lamp.turnOn(); // Нарушение DIP — жёсткая зависимость от класса Lamp
    }
}

В данном случае класс Switch напрямую зависит от конкретной реализации класса Lamp. Если потребуется заменить лампу на другое устройство (например, вентилятор), придётся модифицировать код Switch.

Используем интерфейс для абстрагирования устройств:

public interface Switchable {
    void turnOn();
}

public class Lamp implements Switchable {
    @Override
    public void turnOn() {
        // Лампа включена
    }
}

public class Fan implements Switchable {
    @Override
    public void turnOn() {
        // Вентилятор включен
    }
}

Теперь Switch зависит от интерфейса Switchable, а не от конкретного класса:

public class Switch {
    private Switchable device;

    public Switch(Switchable device) {
        this.device = device;
    }

    public void toggle() {
        device.turnOn(); // Зависимость инверсирована — Switch работает с абстракцией
    }
}

Для изменения устройства достаточно передать новую реализацию интерфейса Switchable при создании объекта Switch, не модифицируя его код.


Мета информация

Область:: ../../meta/zero/00 Архитектура ПО Родитель:: SOLID Источник:: Создана:: 2024-09-27 Автор::

Дополнительные материалы

Дочерние заметки