Принципы SOLID на пальцах. Подготовка к собеседованию.

Почти всегда на собеседовании у программиста, который должен будет использовать ООП, спрашивают детально не только о том, что такое ООП, но и о самих принципах SOLID. Знание этих принципов очень важно для того чтобы писать качественный, поддерживаемый код. Поэтому я постараюсь помочь вам в подготовке к собеседованию, где вы сможете понять, вспомнить и применить прицнипы SOLİD в случае необходимости.

Объектно ориентированное программирование создало возможность программистам комбинировать сущности, которые разделяют общую цель или функционал. Но использование объектно ориентированного подхода не гарантирует качественную кодовую базу.

Запутанный, непонятный и тяжело поддерживаемый код также создается и с применением ООП.

Знаменитый автор книг по качественной разработке приложений, Роберт Мартин (или дядюшка Боб) разработал 5 главных принципов для ООП. Эти принципы были названы акронимом SOLID.

S — Single Responsibility Principle — (Принцип единственной ответственности)
O — Open-Closed Principle (Принцип открытости-закрытости)
L — Liskov Substitution Principle — (Принцип подстановки Барбары Лисков)
I — Interface Segregation Principle — (Принцип разделения интерфейсов)
D — Dependency Inversion Principle — (Принцип инверсии зависимостей)

На первый взгляд все кажется запутанным и сложным. Но это не совсем так. Давайте попробуем разобрать каждый из принципов отдельно.

Что такое хороший код?

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

Давайте начнем разбирать эти принципы:

Принцип единственной ответственности

Класс должен отвечать лишь за одну задачу. Если вдруг класс будет решать сразу несколько задач, то его подсистемы, которые реализуют решение этих задач, будут связанными друг с другом.
И если изменить что-либо в одной из этих подсистем, то придется изменять и другие… Что уже означает что качество кода стало хуже.
Все примеры в этой статье будут абстрактными, без кода.

Давайте рассмотрим следующий пример.

У нас есть класс Computer, который содержит в себе несколько методов:

Single Responsibility principle

Такой класс может в конце концов превратиться в огромный класс, который содержит в себе множество различных методов, которые отвечают за разные части нашего компьютера. Другими словами — мы нарушаем принцип единственной ответственности, комбинируя множество методов (функций) в одном классе.

Как мы можем решить эту проблему?

  • Мы можем разделить класс Computer на множество классов:
SOLID, Single Responsibility Principle

Таким образом, каждый класс описывает тот объект, который имеет лишь одну ответственность.

Принцип открытости-закрытости

  • Принцип открытости-закрытости гласит — Класс должен быть открыт для расширения и закрыт для изменения;
  • Принцип способствует повторному использованию программных компонентов;
  • Когда вы разделяете ответственность класса, вы должны это сделать это таким образом, чтобы поведение класса могло быть расширено или заменено;

Например, создадим наследование, построенное таким образом:

SOLID, Open-Closed principle

В каждом подтипе компьютера, мы сможем написать специальные методы, специфичные для каждого из них.

Принцип подстановки Барбары Лисков

Принцип подстановки Барбары Лисков гласит:

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

Например:

Barbara Liskov substitution principle violation

Птицы «Пингвин» и «Утка», — обе наследуются от контракта (интерфейса) «Птица», который воплощает в себе функцию Fly (лететь).
Но пингвины летать не умеют, потому, планируя шаблон абстрактной птицы, мы нарушили принцип подстановки Барбары Лисков.

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

Принцип разделения интерфейсов

Принцип разделения интерфейсов, грубо говоря, подразумевает, что лучше иметь много специфических интерфейсов (контрактов), чем мало обобщающих.
Также этот принцип позволяет разделять ответственность класса без нарушения принципа подстановки Барбары Лисков.

Пример:

SOLID, Interface Segregation principle

Теперь мы знаем, что можно разделить птиц на виды, такие как летающие и не летающие.
И затем унаследовать (или имплементировать) шаблоны летающих и нелетающих птиц, создав пингвина и утку.

Принцип инверсии зависимостей

Принцип инверсии зависимостей гласит:

  • Абстракции не должны зависеть от деталей, — детали должны зависеть от абстракций

Основная цель принципа — уменьшение зацепления (количества зависимостей) между программными компонентами.

Во всех местах, где один класс использует другой, — используйте его через интерфейс. Это поможет избавиться от лишних зависимостей.

Применение этого принципа уменьшает количество флагов и настроек в системе.