Принципы S.O.L.I.D в картинках
Если вы знакомы с Объектно-ориентированным программированием, то вы, вероятно, слышали о принципах SOLID. Я ранее писал об этом статью, где рассматривал эти принципы с примерами кода. Эта статья, мне кажется, получилась отличным дополнением. Здесь, я, в простой, понятной манере, на картинках покажу, что есть SOLID и с чем его солят.
Эти пять принципов разработки программного обеспечения являются руководством, которому нужно следовать при создании программного обеспечения, чтобы его было легче масштабировать и поддерживать. Они были сделаны популярными инженером-программистом Робертом К. Мартином.
В Интернете так много замечательных статей о SOLID, но я редко вижу примеры с картинками. Научно доказано, что информация проще всего усваивается с помощью визуальной памяти. Так почему, нам не рассмотреть принципы S.O.L.I.D на картинках.
Поэтому основная цель этой статьи - лучше понять эти принципы, используя иллюстрации для подчеркивания ключевой цели для каждого принципа.
Понимаете, некоторые из этих принципов могут выглядеть похожими, но они не преследуют одну и ту же цель. Можно удовлетворить один принцип, нарушая другой, даже если они похожи.
Для простоты изложения я буду использовать слово "Класс", но обратите внимание, что в этой статье оно также может относиться и к функции, методу или модулю.
Принципы SOLID
S - Единая ответственность
Класс должен нести единственную ответственность
Если у класса много обязанностей, это увеличивает вероятность возникновения ошибок, потому что внесение изменений в одну из его обязанностей, может повлиять на другую без вашего ведома.
Цель
Этот принцип направлен на разделение поведения таким образом, чтобы в случае возникновения ошибок в результате ваших изменений, это не повлияло на другие, не связанные с этим обязанности.
O — Принцип открытости/закрытости
Классы должны быть открыты для расширения, но закрыты для модификации.
Изменение текущего поведения класса повлияет на все системы, использующие этот класс.
Если вы хотите, чтобы Класс выполнял больше функций, то идеальным подходом является добавление нового функционала к уже существующим функциям НЕ изменять существующие.
Цель
Этот принцип направлен на расширение поведения Класса без изменения существующего поведения этого Класса. Это сделано для того, чтобы избежать возникновения ошибок везде, где используется данный класс.
Л - Принцип подстановки Барбары Лисков
Если S является подтипом T, то объекты типа T в программе могут быть заменены объектами типа S без изменения каких-либо дополнительных свойств этой программы.
Когда дочерний класс не может выполнять те же действия, что и его родительский класс, это может привести к ошибкам.
Если вы имеете класс и создаете другой класс из него, он становится родителем, а новый класс становится дочерним. Дочерний класс должен быть в состоянии сделать все, что может сделать родительский класс. Этот процесс называется Наследованием.
Дочерний класс должен быть способен обрабатывать те же самые запросы и выдавать тот же самый результат, что и родительский класс, или он может выдать результат, который имеет тот же самый тип.
Рисунок показывает, что родительский класс приносит кофе (это может быть любой тип кофе). Для дочернего класса приемлемо приносить капучино, потому что это специфический тип кофе, но НЕ приемлемо доставлять воду.
Если дочерний класс не соответствует этим требованиям, это означает, что дочерний класс полностью изменяется и нарушает этот принцип.
Цель
Этот принцип направлен на обеспечение последовательности, чтобы родительский класс или его дочерний класс могли использоваться одинаковым образом, и были взаимозаменяемы, без каких-либо ошибок.
I - Сегрегация интерфейсов
Клиенты не должны зависеть от методов, которые они не используют.
Когда от Класса требуется выполнение действий, которые он не должен делать, или не может, это расточительно и может привести к неожиданным ошибкам. Очень часто бывает, что Класс не имеет возможности выполнить эти действия, хотя интерфейс обязует что-то с этим делать.
Класс должен выполнять только те действия, которые необходимы для выполнения его функции. Любое другое действие должно быть полностью удалено или перемещено куда-либо еще, если оно может быть использовано другим классом в будущем.
То есть, главный посыл в этом - разделение толстых интерфейсов, которые "делают всё", на более узконаправленные интерфейсы, решающие узконаправленную задачу.
Цель
Этот принцип направлен на разделение набора действий на более мелкие наборы таким образом, чтобы класс выполнял ТОЛЬКО тот набор действий, который ему нужен.
D - Принцип инверсии зависимостей
- Высокоуровневые модули не должны зависеть от более низкоуровневых модулей. Оба должны зависеть от абстракции.
- Абстракции не должны зависеть от деталей. Детали должны зависеть от абстракций.
Во-первых, давайте определим термины, используемые здесь, проще.
Высокроуровневый Модуль(или класс): Класс, выполняющий действие с помощью инструмента.
Низкоуровневый модуль (или класс): Инструмент, необходимый для выполнения действия.
Абстракция: Представляет собой интерфейс, соединяющий два класса.
Детали: То, как работает инструмент.
Этот принцип гласит, что класс не должен смешиваться с инструментом, который он использует для выполнения действия. Скорее, он должен быть объединен с интерфейсом, который позволит инструменту соединиться с классом.
Он также говорит, что и класс, и интерфейс не должны знать, как работает инструмент. Однако, инструмент должен соответствовать спецификации интерфейса.
Цель
Этот принцип направлен на уменьшение зависимости высокоуровневого класса от низкоуровневого путем внедрения интерфейса.
Резюме
До сих пор мы обсуждали эти пять принципов и подчеркивали их цели. Они призваны помочь вам сделать ваш код простым в настройке, расширении и тестировании без особых проблем.
Большое спасибо за чтение. Я надеюсь, что у вас появилось более полное представление об этой теме, и вам было так же весело читать ее, как и мне.