К какому из принципов SOLID относится Depends
Комментарии (1)
Ответ сгенерирован нейросетью и может содержать ошибки
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 приложениях.