Ответ
Это тесно связанные, но разные концепции. Их можно описать так: DIP — это принцип (что делать), а DI — это паттерн (как это сделать).
1. Принцип инверсии зависимостей (Dependency Inversion Principle - DIP)
Это пятый принцип SOLID. Он гласит:
A. Модули верхнего уровня не должны зависеть от модулей нижнего уровня. Оба должны зависеть от абстракций. B. Абстракции не должны зависеть от деталей. Детали должны зависеть от абстракций.
Проще говоря, вместо того чтобы высокоуровневый класс Service
напрямую зависел от низкоуровневого PostgresDatabase
, оба должны зависеть от общего интерфейса (абстракции), например, DatabaseInterface
.
2. Внедрение зависимостей (Dependency Injection - DI)
Это паттерн проектирования, который является одним из способов реализации DIP. Суть DI в том, что зависимости (объекты, от которых зависит класс) не создаются внутри самого класса, а внедряются в него извне.
Основные типы DI:
- Через конструктор (Constructor Injection): зависимость передается как аргумент в
__init__
. - Через метод (Setter Injection): зависимость устанавливается через специальный метод (сеттер).
- Через свойство (Property Injection): зависимость устанавливается напрямую в публичное свойство.
Пример (реализация DIP через DI)
from abc import ABC, abstractmethod
# 1. Создаем абстракцию (согласно DIP)
class IMessageSender(ABC):
@abstractmethod
def send(self, message: str):
pass
# 2. Создаем конкретные реализации (детали)
class EmailSender(IMessageSender):
def send(self, message: str):
print(f"Отправка по Email: {message}")
class SmsSender(IMessageSender):
def send(self, message: str):
print(f"Отправка по SMS: {message}")
# 3. Высокоуровневый модуль зависит от абстракции
class NotificationService:
# Зависимость IMessageSender внедряется через конструктор (DI)
def __init__(self, sender: IMessageSender):
self._sender = sender
def notify(self, message: str):
self._sender.send(message)
# Использование:
email_sender = EmailSender()
notification_service = NotificationService(email_sender) # Внедрили зависимость
notification_service.notify("Hello via Email!")
# Легко заменяем зависимость без изменения NotificationService
sms_sender = SmsSender()
notification_service_sms = NotificationService(sms_sender)
notification_service_sms.notify("Hello via SMS!")
Итог: DI — это практический инструмент, который позволяет следовать принципу DIP, делая код слабо связанным, гибким и легко тестируемым.