Ответ
Принцип инверсии зависимостей (DIP) — это один из принципов SOLID. Он гласит:
- Модули верхнего уровня не должны зависеть от модулей нижнего уровня. Оба должны зависеть от абстракций.
- Абстракции не должны зависеть от деталей. Детали должны зависеть от абстракций.
Цель — уменьшить связность между компонентами, сделав систему более гибкой, расширяемой и удобной для тестирования.
Пример: Система оповещений
Без DIP (жёсткая зависимость):
// Низкоуровневый модуль
class EmailService {
public void sendEmail(String message) { /* ... */ }
}
// Высокоуровневый модуль напрямую зависит от низкоуровневого
class NotificationService {
private EmailService emailService = new EmailService(); // Прямая зависимость
public void notify(String message) {
emailService.sendEmail(message);
}
}
// Добавление SMS требует изменения NotificationService.
С применением DIP (зависимость от абстракции):
// 1. Абстракция (интерфейс), от которой зависят оба уровня
interface MessageSender {
void send(String message);
}
// 2. Низкоуровневые модули реализуют абстракцию
class EmailService implements MessageSender {
@Override
public void send(String message) { /* ... */ }
}
class SmsService implements MessageSender {
@Override
public void send(String message) { /* ... */ }
}
// 3. Высокоуровневый модуль зависит только от абстракции
class NotificationService {
private MessageSender sender; // Зависимость от абстракции
// 4. Внедрение зависимости (через конструктор)
public NotificationService(MessageSender sender) {
this.sender = sender;
}
public void notify(String message) {
sender.send(message); // Работает с любой реализацией
}
}
// Использование. Конкретная реализация "инвертируется" и внедряется извне.
public class App {
public static void main(String[] args) {
MessageSender sender = new SmsService(); // Легко заменить на EmailService
NotificationService service = new NotificationService(sender);
service.notify("Hello!");
}
}
Итог: NotificationService (верхний уровень) и EmailService/SmsService (нижний уровень) зависят от общего интерфейса MessageSender. Управление зависимостями передаётся внешнему коду (например, контейнеру IoC в Spring), что соответствует инверсии управления (IoC).