Ответ
В луковой архитектуре внедрение зависимостей (Dependency Injection, DI) происходит на границах слоев и следует Принципу инверсии зависимостей (Dependency Inversion Principle). Внутренние слои не зависят от внешних; вместо этого все слои зависят от абстракций.
Механизм DI
- Определение Абстракции (Порт): Во внутреннем слое (например,
application
илиdomain
) определяется абстрактный интерфейс. В Python это обычноabc.ABC
илиtyping.Protocol
. - Реализация (Адаптер): Во внешнем, инфраструктурном слое (
infrastructure
) создается конкретный класс, который реализует этот интерфейс (например, для работы с базой данных или внешним API). - Внедрение: Зависимость (конкретная реализация) передается в конструктор класса внутреннего слоя. Это позволяет внутреннему слою работать с абстракцией, не зная о деталях реализации.
- Сборка (Composition Root): В самой внешней точке приложения (например, в
main.py
или с помощью DI-контейнера) создаются экземпляры конкретных реализаций и внедряются в сервисы.
Пример на Python
from abc import ABC, abstractmethod
# === Domain Layer: Сущность ===
class User:
def __init__(self, name: str):
self.name = name
# === Application Layer: Абстракция (Порт) ===
class UserRepository(ABC):
@abstractmethod
def get_user(self, user_id: int) -> User:
...
# === Infrastructure Layer: Конкретная реализация (Адаптер) ===
class PostgresUserRepository(UserRepository):
def get_user(self, user_id: int) -> User:
# Логика для получения пользователя из PostgreSQL
print(f"Fetching user {user_id} from PostgreSQL...")
return User(name="John Doe")
# === Application Layer: Сервис, использующий абстракцию ===
class UserService:
# Зависимость внедряется через конструктор
def __init__(self, user_repo: UserRepository):
self._user_repo = user_repo
def process_user(self, user_id: int):
user = self._user_repo.get_user(user_id)
print(f"Processing user: {user.name}")
# === Composition Root: Точка сборки приложения ===
if __name__ == "__main__":
# Создаем конкретную реализацию
db_repository = PostgresUserRepository()
# Внедряем ее в сервис
user_service = UserService(user_repo=db_repository)
# Используем сервис
user_service.process_user(123)