--- aliases: - DIP - Принцип инверсии зависимостей tags: - maturity/🌱 date: 2024-09-27 zero-link: - "[[../../meta/zero/00 Архитектура ПО|00 Архитектура ПО]]" parents: - "[[SOLID|SOLID]]" linked: --- **Принцип инверсии зависимостей (Dependency Inversion Principle, DIP)** гласит: [[высокоуровневые модули]] не должны зависеть от низкоуровневых модулей. Оба должны зависеть от абстракций. Это означает, что вместо использования конкретных реализаций, классы должны работать с абстракциями — интерфейсами или абстрактными классами. DIP делает код более гибким, модульным и легко расширяемым. **Как соблюдать DIP** 1. **Работайте с абстракциями:** Замените зависимости на интерфейсы или абстрактные классы. 2. **Инвертируйте зависимости:** Используйте внедрение зависимостей ([[Dependency Injection]]) через конструктор, сеттер или контейнеры. 3. **Минимизируйте жёсткую связанность:** Высокоуровневые модули должны оставаться независимыми от деталей реализации низкоуровневых модулей. **Преимущества соблюдения DIP** 1. **Гибкость:** Замена низкоуровневых модулей (реализаций) не требует изменения высокоуровневых модулей. 2. **Улучшенная тестируемость:** Высокоуровневые модули можно тестировать с помощью моков или заглушек, так как они зависят от абстракций. 3. **Снижение связанности:** Высокоуровневый код становится независимым от деталей реализации. 4. **Расширяемость:** Новые реализации интерфейсов можно добавлять без изменений в существующем коде. ## Пример нарушения DIP Рассмотрим пример с выключателем, который управляет лампой: ```java 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`. Используем интерфейс для абстрагирования устройств: ```java 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`, а не от конкретного класса: ```java public class Switch { private Switchable device; public Switch(Switchable device) { this.device = device; } public void toggle() { device.turnOn(); // Зависимость инверсирована — Switch работает с абстракцией } } ``` Для изменения устройства достаточно передать новую реализацию интерфейса `Switchable` при создании объекта `Switch`, не модифицируя его код. *** ## Мета информация **Область**:: [[../../meta/zero/00 Архитектура ПО|00 Архитектура ПО]] **Родитель**:: [[SOLID]] **Источник**:: **Создана**:: [[2024-09-27]] **Автор**:: ### Дополнительные материалы - ### Дочерние заметки