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

К какому из принципов SOLID относится Depends

1.7 Middle🔥 61 комментариев
#FastAPI и Flask#Архитектура и паттерны

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

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

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

Depends и принцип DI (Dependency Inversion)

Depends в FastAPI относится к Dependency Inversion Principle (DIP) — пятому принципу SOLID. Это механизм инъекции зависимостей (Dependency Injection), который реализует именно DIP.

Что такое Dependency Inversion?

Оригинальное определение:

Модули высокого уровня не должны зависеть от модулей низкого уровня. Оба должны зависеть от абстракций. Абстракции не должны зависеть от деталей. Детали должны зависеть от абстракций.

Просто говоря: код должен зависеть от интерфейсов, а не от конкретных реализаций.

Как Depends реализует DIP

Без Depends — жёсткие зависимости:

class DatabaseRepository:
    def __init__(self):
        self.db = Database()  # Конкретная реализация жёстко закодирована
    
    def get_user(self, user_id: int):
        return self.db.query("SELECT * FROM users WHERE id = ?", user_id)

class UserService:
    def __init__(self):
        self.repo = DatabaseRepository()  # Зависит от конкретного класса
    
    def get_user_data(self, user_id: int):
        return self.repo.get_user(user_id)

# В router — нужно создавать всё вручную
@app.get("/users/{user_id}")
def get_user(user_id: int):
    service = UserService()  # Жёсткое связывание
    return service.get_user_data(user_id)

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

С Depends — инверсия управления:

from typing import Annotated
from fastapi import Depends

# Абстракция — протокол
class UserRepository(Protocol):
    def get_user(self, user_id: int) -> User: ...

# Конкретная реализация
class DatabaseRepository:
    def get_user(self, user_id: int) -> User:
        return db.query(User).filter(User.id == user_id).first()

class UserService:
    def __init__(self, repo: UserRepository):
        self.repo = repo  # Зависит от абстракции (Protocol)
    
    def get_user_data(self, user_id: int) -> User:
        return self.repo.get_user(user_id)

# Функция для инъекции
def get_user_service(repo: Annotated[UserRepository, Depends(get_repository)]) -> UserService:
    return UserService(repo)

# Получение репозитория
def get_repository() -> UserRepository:
    return DatabaseRepository()  # Легко менять на MockRepository для тестов

# В router — чистый код
@app.get("/users/{user_id}")
def get_user(
    user_id: int,
    service: Annotated[UserService, Depends(get_user_service)]
) -> User:
    return service.get_user_data(user_id)  # Service внедрена, не создаём вручную

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

1. Слабая связанность (Loose Coupling)

# Тестирование просто
class MockRepository(UserRepository):
    def get_user(self, user_id: int) -> User:
        return User(id=user_id, name="Test User")

# Подменяем в тестах
def get_test_service() -> UserService:
    return UserService(MockRepository())

2. Гибкость реализации

def get_repository() -> UserRepository:
    if is_testing():
        return MockRepository()
    elif use_redis():
        return CachedRepository()
    else:
        return DatabaseRepository()

3. Читаемость и простота

# Явно видно, какие зависимости нужны функции
@app.post("/auth/login")
def login(
    credentials: LoginSchema,
    auth_service: Annotated[AuthService, Depends(get_auth_service)],
    db: Annotated[Session, Depends(get_db)],
    cache: Annotated[Redis, Depends(get_redis)],
):
    # Все зависимости внедрены автоматически
    pass

4. Управление жизненным циклом

def get_db() -> Generator[Session, None, None]:
    session = SessionLocal()
    try:
        yield session  # Передаём зависимость
    finally:
        session.close()  # Очищаем после использования

@app.get("/")
def endpoint(db: Annotated[Session, Depends(get_db)]):
    # db закроется автоматически после ответа
    pass

Все 5 принципов SOLID

ПринципОписаниеГде используется
SingleОдин класс = одна ответственностьРазделение UserService и Repository
OpenОткрыт для расширения, закрыт для модификацииProtocol для UserRepository
LiskovДочерние классы заменяемы родительскимиDatabaseRepository вместо UserRepository
InterfaceНе зависеть от ненужных интерфейсовМинимальный Protocol с нужными методами
DependencyЗависимости от абстракцийDepends(get_repository) — DIP в действии

Вывод

Depends — это механизм реализации Dependency Inversion Principle. Это позволяет:

  • Инвертировать управление зависимостями (IoC — Inversion of Control)
  • Делать код тестируемым и гибким
  • Уменьшить связанность компонентов
  • Легко менять реализации без изменения бизнес-логики

Это один из ключевых инструментов для написания чистого и поддерживаемого кода в современных Python приложениях.

К какому из принципов SOLID относится Depends | PrepBro