Комментарии (1)
🐱
claude-haiku-4.5PrepBro AI28 мар. 2026 г.(ред.)
Ответ сгенерирован нейросетью и может содержать ошибки
Что означает D в SOLID?
D в SOLID означает Dependency Inversion Principle (Принцип инверсии зависимостей). Это принцип проектирования, который гласит: высокоуровневые модули не должны зависеть от низкоуровневых модулей. Оба должны зависеть от абстракций.
Суть принципа
Депендency Inversion Principle состоит из двух частей:
- Высокоуровневые модули не должны зависеть от низкоуровневых модулей — оба должны зависеть от абстракций
- Абстракции не должны зависеть от деталей — детали должны зависеть от абстракций
Это инвертирует традиционный способ написания кода, где высокоуровневый код зависит от низкоуровневых деталей реализации.
Пример нарушения принципа
# ❌ Плохо — высокоуровневый код зависит от конкретной реализации
class UserRepository:
def save(self, user):
# Сохранение в PostgreSQL
pass
class UserService:
def __init__(self):
self.repository = UserRepository() # Жёсткая зависимость
def create_user(self, name, email):
user = {"name": name, "email": email}
self.repository.save(user)
# Если захотим использовать MongoDB, придётся менять UserService!
Правильная реализация
# ✅ Хорошо — зависимость от абстракции
from abc import ABC, abstractmethod
from typing import Protocol
# Абстракция (интерфейс)
class IUserRepository(ABC):
@abstractmethod
def save(self, user: dict) -> None:
pass
# Конкретные реализации
class PostgresUserRepository(IUserRepository):
def save(self, user: dict) -> None:
print(f"Saving to PostgreSQL: {user}")
class MongoUserRepository(IUserRepository):
def save(self, user: dict) -> None:
print(f"Saving to MongoDB: {user}")
# Высокоуровневый модуль зависит от абстракции
class UserService:
def __init__(self, repository: IUserRepository):
self.repository = repository # Инъекция зависимости
def create_user(self, name: str, email: str) -> None:
user = {"name": name, "email": email}
self.repository.save(user)
# Использование
if __name__ == "__main__":
# Легко менять реализацию
postgres_repo = PostgresUserRepository()
service1 = UserService(postgres_repo)
service1.create_user("John", "john@example.com")
mongo_repo = MongoUserRepository()
service2 = UserService(mongo_repo)
service2.create_user("Jane", "jane@example.com")
Ещё лучше — использование Protocol (Python 3.8+)
from typing import Protocol
class UserRepository(Protocol):
"""Интерфейс репозитория пользователей"""
def save(self, user: dict) -> None:
...
class PostgresUserRepository:
"""Конкретная реализация для PostgreSQL"""
def save(self, user: dict) -> None:
print(f"Saving to PostgreSQL: {user}")
class UserService:
def __init__(self, repository: UserRepository):
self.repository = repository
def create_user(self, name: str, email: str) -> None:
user = {"name": name, "email": email}
self.repository.save(user)
# Работает благодаря структурной типизации (duck typing + type hints)
repo = PostgresUserRepository()
service = UserService(repo)
Преимущества Dependency Inversion Principle
- Слабая связанность — компоненты не знают о конкретных реализациях
- Тестируемость — легко подставить mock-объекты
class MockUserRepository(IUserRepository):
def save(self, user: dict) -> None:
pass # Не делаем ничего, просто для теста
def test_user_service():
mock_repo = MockUserRepository()
service = UserService(mock_repo)
service.create_user("Test", "test@example.com")
# Тест пройдёт, БД не затронется
- Расширяемость — новые реализации легко добавляются без изменения существующего кода
- Переиспользуемость — высокоуровневый код не привязан к конкретным реализациям
Антипаттерны
# ❌ Создание зависимостей внутри функции
def process_order(order_id):
db = PostgresDatabase() # Жёсткая зависимость
repository = UserRepository(db)
# ...
# ✅ Передача зависимостей
def process_order(order_id, repository: UserRepository):
# ...
Связь с другими принципами SOLID
- Single Responsibility: каждый класс имеет одну ответственность
- Open/Closed: открыт для расширения (новых реализаций), закрыт для модификации
- Liskov Substitution: все реализации могут заменять одна другую
- Interface Segregation: интерфейсы узкие и специфичные
Dependency Inversion — это ключевой принцип для чистого, тестируемого и масштабируемого кода.