Logo Craft Homelab Docs Контакты Telegram
Принципы SOLID в ООП: Полное руководство с примерами
manual
Thu Nov 06 2025

SOLID: Фундамент чистого кода для разработчика

Проектирование сложных систем требует не только знания синтаксиса языка, но и понимания принципов архитектуры. Акноним SOLID, введенный Робертом Мартином, описывает пять ключевых принципов, которые помогают создавать гибкий, масштабируемый и понятный код.

1. S: Single Responsibility Principle (Принцип единственной ответственности)

«Один класс — одна задача».

Каждый класс должен отвечать только за одну область функциональности. Если класс делает слишком много, его части становятся сильно связанными, и изменение одного аспекта может сломать другой.

  • Антипаттерн: Класс Animal, который одновременно хранит свойства животного и содержит логику сохранения его в базу данных.
  • Решение: Разделить ответственность. Создать класс Animal для описания сущности и класс AnimalDB для работы с хранилищем.

2. O: Open-Closed Principle (Принцип открытости-закрытости)

«Программные сущности должны быть открыты для расширения, но закрыты для модификации».

Вы должны иметь возможность добавлять новое поведение в систему, не переписывая уже существующий и протестированный код.

  • Антипаттерн: Функция, которая рассчитывает звуки животных через длинный список if-else или switch по типам. При добавлении нового животного функцию приходится менять.
  • Решение: Использовать полиморфизм. Создать абстрактный метод makeSound() в базовом классе и реализовывать его в наследниках. Теперь функция просто вызывает метод, не зная деталей реализации.

3. L: Liskov Substitution Principle (Принцип подстановки Барбары Лисков)

«Наследники должны быть взаимозаменяемы с базовыми классами».

Функции, использующие базовый тип, должны иметь возможность работать с его подклассами, не зная об этом и не нарушая логику программы.

  • Антипаттерн: Если в функции вам приходится проверять тип объекта (if object is Lion), значит, вы нарушили этот принцип.
  • Решение: Проектировать интерфейсы так, чтобы подклассы полностью соответствовали ожиданиям родительского класса. Все специфичное поведение должно быть скрыто за абстрактным методом, единым для всех.

4. I: Interface Segregation Principle (Принцип разделения интерфейса)

«Много специализированных интерфейсов лучше, чем один универсальный».

Клиенты не должны зависеть от методов, которые они не используют. Громоздкие интерфейсы (“толстые интерфейсы”) заставляют классы реализовывать пустые методы-заглушки.

  • Антипаттерн: Общий интерфейс Shape, который требует реализации методов drawCircle(), drawSquare() и drawTriangle() одновременно.
  • Решение: Разбить интерфейс на мелкие: ICircle, ISquare и т.д. Класс должен имплементировать только тот интерфейс, который ему действительно нужен.

5. D: Dependency Inversion Principle (Принцип инверсии зависимостей)

«Зависьте от абстракций, а не от конкретных реализаций».

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

  • Антипаттерн: Класс Http напрямую создает экземпляр XMLHttpService. Если вам понадобится заменить его на другой сервис (например, для тестов), придется переписывать код класса Http.
  • Решение: Создать интерфейс Connection. Класс Http будет принимать в конструкторе объект типа Connection. Теперь мы можем передать любую реализацию (Node.js сервис, заглушку, Fetch), не меняя логику Http.

Итог: зачем это нужно?

Соблюдение SOLID превращает «спагетти-код» в модульную систему. Это:

  1. Снижает стоимость поддержки: изменения в одной части системы меньше влияют на другие.
  2. Упрощает тестирование: мелкие классы с одной задачей легче покрыть тестами.
  3. Повышает читаемость: код становится предсказуемым и понятным для новых разработчиков.