Ответ
Применял SOLID для создания поддерживаемого и тестируемого кода. Каждый принцип решает конкретные проблемы:
- Single Responsibility (SRP) – Класс/функция отвечает за одну задачу. Например, разделил логику валидации данных и их сохранения в разные классы.
- Open/Closed (OCP) – Код открыт для расширения, но закрыт для модификации. Использовал абстрактные классы или интерфейсы, чтобы добавлять новое поведение через наследование или композицию, не меняя существующий код.
- Liskov Substitution (LSP) – Объекты базового класса можно заменять объектами производных классов без изменения корректности программы. Следил, чтобы переопределенные методы в наследниках не ужесточали предусловия и не ослабляли постусловия.
- Interface Segregation (ISP) – Много специализированных интерфейсов лучше одного общего. Вместо одного «толстого» интерфейса
IReportсоздалIPrintable,IExportable,ISavable. - Dependency Inversion (DIP) – Модули верхнего уровня не зависят от модулей нижнего уровня. Оба зависят от абстракций. Внедрял зависимости через конструктор или метод.
Практический пример DIP:
from abc import ABC, abstractmethod
# Абстракция (интерфейс)
class NotificationService(ABC):
@abstractmethod
def send(self, message: str):
pass
# Модуль нижнего уровня (деталь)
class EmailService(NotificationService):
def send(self, message: str):
print(f"Sending email: {message}")
# Модуль верхнего уровня (логика)
class UserNotifier:
def __init__(self, notifier: NotificationService): # Зависим от абстракции
self._notifier = notifier
def notify_user(self, user_data: dict):
message = f"Hello, {user_data['name']}!"
self._notifier.send(message) # Используем абстракцию
# Использование
email_service = EmailService()
notifier = UserNotifier(email_service) # Внедряем конкретную реализацию
notifier.notify_user({"name": "Alice"})
Результат: Код стал менее связанным, его проще тестировать (можно подменить NotificationService на мок) и расширять (добавить SmsService).