digital-garden/dev/architecture/Dependency Inversion Principle.md
Struchkov Mark 2c945630a3
Some checks failed
continuous-integration/drone/push Build is failing
continuous-integration/drone Build is passing
Обновление и рефакторинг
2024-11-23 21:34:40 +03:00

102 lines
4.8 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

---
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]]
**Автор**::
### Дополнительные материалы
-
### Дочерние заметки
<!-- QueryToSerialize: LIST FROM [[]] WHERE contains(Родитель, this.file.link) or contains(parents, this.file.link) -->