Ответ
Внедрение зависимостей (Dependency Injection, DI) — это паттерн проектирования, при котором зависимости (объекты, необходимые для работы) передаются классу извне, а не создаются им самим. Это реализация принципа инверсии управления (Inversion of Control, IoC), которая делает код менее связанным, более гибким и легко тестируемым.
Ключевая идея: Класс не должен знать, как создавать свои зависимости, он должен только получать их готовыми.
Пример на Python
Плохой подход (без DI): Класс UserService
жестко связан с конкретной реализацией Database
.
class Database:
def get_user(self, user_id: int) -> str:
# Логика получения данных из реальной БД
return f"User data for {user_id}"
class UserService:
def __init__(self):
# Зависимость создается прямо внутри класса
self.db = Database()
def process_user(self, user_id: int):
user_data = self.db.get_user(user_id)
print(f"Processing: {user_data}")
Хороший подход (с DI): Зависимость db
передается через конструктор.
# Абстракция зависимости (не обязательно, но хорошая практика)
from abc import ABC, abstractmethod
class UserDatabase(ABC):
@abstractmethod
def get_user(self, user_id: int) -> str:
pass
# Конкретная реализация
class RealDatabase(UserDatabase):
def get_user(self, user_id: int) -> str:
return f"User data for {user_id}"
class UserService:
# Зависимость передается извне и типизируется абстракцией
def __init__(self, db: UserDatabase):
self.db = db
def process_user(self, user_id: int):
user_data = self.db.get_user(user_id)
print(f"Processing: {user_data}")
# Использование:
# DI-контейнер или вызывающий код создает и "внедряет" зависимость
real_db = RealDatabase()
service = UserService(db=real_db)
service.process_user(101)
Основные преимущества DI:
- Упрощение тестирования: В тестах можно легко подменить реальную базу данных на mock-объект (
MockDatabase
). - Снижение связанности (Loose Coupling):
UserService
не зависит от конкретной реализацииRealDatabase
, а только от абстракцииUserDatabase
. - Повышение гибкости: Можно легко заменить
RealDatabase
на другую реализацию (например,PostgresDatabase
), не меняя кодUserService
.