5 принципов объектно-ориентированного программирования (ООП) SOLID

5 принципов программирования: SOLID

5 принципов программирования: SOLID

На митапе про технические собеседования часто поднималась тема SOLID. На следующее наше мероприятие мы пригласили спикеров из EPAM, Squire Technologies и Plarium рассказать о принципах SOLID, как их понимать, и для чего они вообще нужны. Суммируем и анализируем главные мысли, прозвучавшие на митапе. SOLID – это 5 принципов объектно-ориентированного программирования. Из них растут почти все паттерны проектирования. На митапе прозвучало мнение, что SOLID больше про менеджмент и принятие решений, и нам это нравится. Красивая аббревиатура складывается из пяти фундаментальных понятий:

  • S (The Single Responsibility Principle) – принцип единой ответственности (SRP). Каждая структура должна иметь лишь одну цель и единственную причину для изменения. Этот принцип чаще всего работает ещё на этапе проектирования: предусматриваем все способы изменения класса, когда продумываем каждую структуру в отдельности.
  • O (The Open Closed Principle) – обозначает принцип открытости/закрытости (OCP). Класс должен быть открыт для расширений, закрыт – для модификаций. Модуль разрабатываем так, чтобы новая функциональность могла быть добавлена только при создании новых требований. Пример: допустим, мы работаем с отчетами.  Есть некий класс, отвечающий за генерацию отчетов. В зависимости от входных параметров программа формирует определенный тип отчета. Генератор принимает параметры и в зависимости от них генерирует необходимую форму. При появлении новых требований (нужно создать новый тип отчета) создаем новый класс.
  • L (The Liskov Substitution Principle) – принцип подстановки Лисков, описывающий возможности заменяемости экземпляров объектов (LSP). Он же дает некое понятие корректности работы системы. Если в программе есть тип А, его наследник тип Б и во всех местах, где используем тип А заменим его на Б, то результат работы программы не изменится. Когда создается класс-наследник, он должен расширять функционал базового класса, а не изменять его.
  • I (The Interface Segregation Principle) – принцип разделения интерфейсов (ISP). Лучше иметь много маленьких, специализированных интерфейсов, чем один большой. Если создаем единственный интерфейс, то он имеет доступ всем функциям – это засоряет код и затрачивает вычислительную мощность программы. Тут важно сказать также, что деление интерфейса на неделимые – не всегда хорошо. Нужно ориентироваться на потребности пользователя. Пример с митапа: если программа предполагает всего один тип пользователя и ему удобно работать с одним интерфейсом, то мы оставляем один сложный, но логически понятный интерфейс. Как выделить интерфейсы? Предпочитаем интерфейсы, которые базируются на ролях. Чтобы логика не шла в разрез с семантикой кода, всегда ориентируемся на смысл интерфейса. Если интерфейс потенциально можно разделить на несколько, но смысла в этом нет – не делайте этого. Пример с митапа: делаем игру про животных, в которой каждое действие – отдельный интерфейс: летать, бегать, ходить, ползать и т.д. Смысла в этом нет, т.к. тогда по смыслу ваша программа допускает зверя, который и ползает, и летает одновременно. Всегда разделяем взаимоисключающие понятия.
  • D (The Dependency Inversion Principle) – принцип инверсии зависимостей (DIP). 1. Классы высокого уровня не должны зависеть от классов низкого уровня. 2. Все классы зависят от абстракций. 3. Абстракции не зависят от деталей. 4. Детали должны зависеть от абстракций.

Зависимость классов – это ссылка внутри одного класса на другой в исходном коде. Классы высокого уровня – это классы, реализующие бизнес-логику или логику в системе. Классы низкого уровня – это классы, которые занимаются более низкоуровневыми операциями: взаимодействуют с базой данных, передают сигналы в операционную систему и т.д. Когда высокоуровневый класс явно ссылается на низкоуровневый высока вероятность, что изменения в одном классе нарушат работу другого.  Поэтому мы всегда держим их друг от друга настолько далеко, насколько можем. Принципы SOLID сокращают временные затраты на внесение изменений в код, делают его удобным для работы, адаптируемым к изменениям.