← Назад к вопросам

Что такое dependency inversion principle?

1.0 Junior🔥 231 комментариев
#SOLID и паттерны проектирования

Комментарии (1)

🐱
claude-haiku-4.5PrepBro AI22 мар. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Dependency Inversion Principle (DIP)

Dependency Inversion Principle — один из пяти SOLID принципов, сформулированный Робертом Мартином. Этот принцип говорит, что высокоуровневые модули не должны зависеть от низкоуровневых модулей. Оба должны зависеть от абстракций. Кроме того, абстракции не должны зависеть от деталей, а детали должны зависеть от абстракций.

Проблема без DIP

Представь, что у тебя есть сервис доставки, который напрямую зависит от конкретной реализации:

public class DeliveryService {
    private EmailNotifier emailNotifier = new EmailNotifier();
    private SmsNotifier smsNotifier = new SmsNotifier();
    
    public void notifyCustomer(Order order) {
        emailNotifier.send(order.getCustomerEmail());
        smsNotifier.send(order.getCustomerPhone());
    }
}

Проблемы:

  • DeliveryService жёстко привязан к конкретным классам EmailNotifier и SmsNotifier
  • Сложно тестировать (нельзя подменить реальные сервисы)
  • Сложно добавить новый способ уведомления (например, Telegram)
  • Изменение в EmailNotifier может сломать DeliveryService

Решение с DIP

Мы вводим абстракцию (интерфейс) и зависим от неё:

public interface Notifier {
    void send(String recipient);
}

public class EmailNotifier implements Notifier {
    @Override
    public void send(String email) {
        // отправка email
    }
}

public class SmsNotifier implements Notifier {
    @Override
    public void send(String phone) {
        // отправка SMS
    }
}

public class DeliveryService {
    private List<Notifier> notifiers;
    
    // Инъекция зависимостей через конструктор
    public DeliveryService(List<Notifier> notifiers) {
        this.notifiers = notifiers;
    }
    
    public void notifyCustomer(Order order) {
        for (Notifier notifier : notifiers) {
            notifier.send(order.getCustomerInfo());
        }
    }
}

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

  1. Слабая связанностьDeliveryService зависит от интерфейса, а не от конкретных классов
  2. Лёгче тестировать — можно создать Mock-реализацию Notifier
  3. Легче расширять — добавить TelegramNotifier без изменения DeliveryService
  4. Гибкость конфигурации — в runtime можно выбрать, какие notifiers использовать

Пример с тестированием

@Test
public void testCustomerNotification() {
    // Mock-реализация
    Notifier mockNotifier = new Notifier() {
        @Override
        public void send(String recipient) {
            // Проверяем, что метод вызвался
        }
    };
    
    DeliveryService service = new DeliveryService(Arrays.asList(mockNotifier));
    Order order = new Order("customer@email.com");
    service.notifyCustomer(order); // Работает с mock
}

Правильный вектор зависимостей

Вместо:

DeliveryService → EmailNotifier → SMTP
                → SmsNotifier → SMS API

Мы получаем:

DeliveryService → Notifier (интерфейс)
                  ↑
        EmailNotifier, SmsNotifier (реализации зависят от интерфейса)

Связь с другими SOLID принципами

  • S (Single Responsibility) — каждый Notifier имеет одну ответственность
  • O (Open/Closed) — система открыта для новых реализаций (новых Notifier)
  • L (Liskov Substitution) — любая реализация Notifier заменяема
  • I (Interface Segregation) — интерфейс Notifier минимален и сфокусирован

DIP — это фундамент архитектуры, позволяющий создавать гибкие, тестируемые и поддерживаемые системы.

Что такое dependency inversion principle? | PrepBro