Что такое SOLID?

«Что такое SOLID?» — вопрос из категории ООП, который задают на 26% собеседований Data Scientist / ML Инженер. Ниже — развёрнутый ответ с разбором ключевых моментов.

Ответ

SOLID — это пять ключевых принципов объектно-ориентированного проектирования, направленных на создание понятного, гибкого и поддерживаемого кода.

Принципы:

  1. Принцип единственной ответственности (Single Responsibility Principle, SRP): Класс должен иметь одну и только одну причину для изменения. Это означает, что он должен решать одну конкретную задачу.

    • Проблема: Класс Report, который и вычисляет данные, и сохраняет их в файл.
    • Решение: Разделить на ReportCalculator и ReportSaver.
  2. Принцип открытости/закрытости (Open/Closed Principle, OCP): Классы должны быть открыты для расширения (через наследование, композицию) и закрыты для модификации. Новый функционал добавляется новыми классами, а не изменением существующих.

    • Пример: Вместо добавления if-else в метод calculateDiscount() для каждого типа клиента, создать абстрактный класс DiscountStrategy и конкретные реализации RegularDiscount, PremiumDiscount.
  3. Принцип подстановки Барбары Лисков (Liskov Substitution Principle, LSP): Объекты базового класса должны быть заменяемы объектами его подклассов без нарушения корректности программы. Наследник не должен ужесточать предусловия или ослаблять постусловия родителя.

    • Нарушение: Класс Square, наследующий от Rectangle. Если у Rectangle есть сеттеры setWidth() и setHeight(), то для Square они нарушают инвариант (ширина всегда равна высоте).
  4. Принцип разделения интерфейса (Interface Segregation Principle, ISP): Много специализированных интерфейсов лучше одного общего. Клиент не должен зависеть от методов, которые он не использует.

    • Пример: Вместо монолитного интерфейса IMultifunctionPrinter с методами print(), scan(), fax(), создать отдельные IPrinter, IScanner, IFaxMachine.
  5. Принцип инверсии зависимостей (Dependency Inversion Principle, DIP): Модули верхнего уровня не должны зависеть от модулей нижнего уровня. Оба должны зависеть от абстракций. Абстракции не должны зависеть от деталей, детали должны зависеть от абстракций.

    • Пример: Класс OrderService должен зависеть от интерфейса INotificationService, а не от конкретного класса EmailNotificationService. Это позволяет легко подменить реализацию на SmsNotificationService.

Практическая польза: Следование SOLID облегчает рефакторинг, модульное тестирование и коллективную разработку, снижая связность кода и повышая его переиспользуемость.

Видео-ответы