4.8 KiB
aliases | tags | date | zero-link | parents | linked | |||||
---|---|---|---|---|---|---|---|---|---|---|
|
|
2024-09-27 |
|
|
Принцип инверсии зависимостей (Dependency Inversion Principle, DIP) гласит: высокоуровневые модули не должны зависеть от низкоуровневых модулей. Оба должны зависеть от абстракций. Это означает, что вместо использования конкретных реализаций, классы должны работать с абстракциями — интерфейсами или абстрактными классами. DIP делает код более гибким, модульным и легко расширяемым.
Как соблюдать DIP
- Работайте с абстракциями: Замените зависимости на интерфейсы или абстрактные классы.
- Инвертируйте зависимости: Используйте внедрение зависимостей (Dependency Injection) через конструктор, сеттер или контейнеры.
- Минимизируйте жёсткую связанность: Высокоуровневые модули должны оставаться независимыми от деталей реализации низкоуровневых модулей.
Преимущества соблюдения DIP
- Гибкость: Замена низкоуровневых модулей (реализаций) не требует изменения высокоуровневых модулей.
- Улучшенная тестируемость: Высокоуровневые модули можно тестировать с помощью моков или заглушек, так как они зависят от абстракций.
- Снижение связанности: Высокоуровневый код становится независимым от деталей реализации.
- Расширяемость: Новые реализации интерфейсов можно добавлять без изменений в существующем коде.
Пример нарушения 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 Автор::