Что такое solid принципы: SOLID — принципы объектно-ориентированного программирования

Содержание

Принципы SOLID в картинках / Хабр

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

В Сети множество отличных статей, где рассказывается о принципах SOLID, но иллюстрированных среди них мне практически не попадалось. Из-за этого таким людям со склонностью к визуальному восприятию информации – таким, как я – бывает сложно схватывать суть и не отвлекаться.

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

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

Ну, приступим.

Принципы SOLID

S – Single Responsibility (Принцип единственной ответственности)

Каждый класс должен отвечать только за одну операцию.

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

Назначение

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

O — Open-Closed (Принцип открытости-закрытости)

Классы должны  быть  открыты для расширения, но закрыты для модификации.

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

Назначение

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

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

Если П является подтипом Т, то любые объекты типа Т, присутствующие в программе, могут заменяться объектами типа П без негативных последствий для функциональности программы.


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

Если у вас имеется класс и вы создаете на его базе другой класс, исходный класс становится родителем, а новый – его потомком. Класс-потомок должен производить такие же операции, как и класс-родитель. Это называется наследственностью.

Необходимо, чтобы класс-потомок был способен обрабатывать те же запросы, что и родитель, и выдавать тот же результат. Или же результат может отличаться, но при этом относиться к тому же типу. На картинке это показано так: класс-родитель подаёт кофе (в любых видах), значит, для класса-потомка приемлемо подавать капучино (разновидность кофе), но неприемлемо подавать воду.

Если класс-потомок не удовлетворяет этим требованиям, значит, он слишком сильно отличается от родителя и нарушает принцип.

Назначение

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

I — Interface Segregation (Принцип разделения интерфейсов)

Не следует ставить клиент в зависимость от методов, которые он не использует.

Когда классу приходится производить действия, не несущие никакой реальной пользы, это выливается в пустую трату ресурса, а в случае, если класс выполнять эти действия не способен, ведёт к возникновению багов.

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

Назначение

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

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

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


Для начала объясню термины, которые здесь применяются, простыми словами.

Модули (или классы) верхнего уровня = классы, которые выполняют операцию при помощи инструмента

Модули (или классы) нижнего уровня = инструменты, которые нужны для выполнения операций

Абстракции – представляют интерфейс, соединяющий два класса

Детали = специфические характеристики работы инструмента

Согласно данному принципу, класс не должен соединяться с инструментом, который применяет для выполнения операции. Вместо этого он должен быть соединён с интерфейсом, который поможет установить связь между инструментом и классом.

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

Назначение

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

Обобщая сказанное


Мы разобрали все пять принципов и сформулировали для каждого назначение. Всё это призвано помочь вам писать код, который можно модифицировать, расширять и тестировать с минимумом проблем. Спасибо, что прочитали; надеюсь, вы получили не меньше удовольствия, чем я в процессе работы над статьёй.

что такое и зачем нужны. Разбираем по буквам

SOLID – это какая-то игра?

Не совсем. SOLID – пять принципов объектно-ориентированного программирования, которые задают архитектуру программы.

Разберем по буквам:

S (The Single Responsibility Principle) – принцип единой ответственности, то есть один класс решает одну задачу и у класса должна быть только одна причина для изменения. Если класс задает направление движения машины, то этот класс не должен выполнять какие-либо другие задачи. Таким образом, данный принцип помогает разбивать общую конструкцию на независимые модули и уменьшать межмодульную связью.

O (The Open Closed Principle) – принцип открытости/замкнутости. Если понадобилось добавить новую функциональность к классу, то существующий класс не модифицируем, а создаем наследника класса с новыми возможностями. То есть у нас должна быть возможность расширять класс без изменения самого класса.

L (The Liskov Substitution Principle) – принцип подстановки Лисков, описывающий возможности заменяемости экземпляров объектов. Простыми словами: дочерний класс должен следовать принципам родительского класса и не изменять их. Пусть у нас есть класс Прямоугольник с методами, задающими ширину, высоту и рассчитывающим площадь. Теперь мы захотели создать класс Квадрат. Квадрат – тот же самый прямоугольник, но с одинаковыми сторонами. Класс Квадрат наследуется от класса Прямоугольник и переопределяет его методы: подставляем значения – все работает. Но если мы начнем использовать класс Прямоугольник в качестве интерфейса, а работать будем с классом Квадрат, мы разом изменяем оба параметра. Чтобы решить эту проблему, создается общий интерфейс для обоих классов и вместо наследования одного класса от другого использовать этот самый интерфейс.

I (The Interface Segregation Principle) – принцип разделения интерфейсов. Создавайте узкоспециализированные интерфейсы и не вынуждайте клиента зависеть от неиспользуемых интерфейсов. Допустим есть класс Auto с методами комплектаций для всех автомобилей. Если мы наследуемся от интерфейса, то все методы реализованные в нем должны быть описаны в классе-потомке. В результате чего классы могут получить ненужные методы. Для решения этой проблемы мы разделяем интерфейсы.

D (The Dependency Inversion Principle) – принцип инверсии зависимостей. Сущности должны зависеть от абстракций, а не от чего-то конкретного. Допустим, у нас есть низкоуровневый класс HTTPService с логикой запроса и высокоуровневый класс HTTP, в конструктор которого мы передаем низкоуровневый модуль. После чего вызываем его методы и нарушаем принцип инверсии зависимости: высокоуровневый модель зависит от низкоуровневого. Для решения проблемы мы создаем отдельный интерфейс и передаем его в высокоуровневый интерфейс. Теперь наш класс не зависит от низкоуровневого модуля.

Я так ничего и не понял, можно объяснить доступно?

Конечно. 20 января мы провели бесплатный вебинар «Простой рабочий алгоритм использования SOLID на практике», на котором подробно рассказали о принципах SOLID. Вот запись вебинара:

Слова, слова, слова… SOLID-принципы нужны, чтобы почувствовать себя умным? Какой профит?

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

Чем дальше в лес, тем больше дров

Помимо SOLID-принципов, разрабу пригодятся паттерны проектирования, тестирование, виды сложности, абстракции и многое другое.

Кстати, 15 февраля стартует наш курс «Архитектуры и шаблоны проектирования», на котором вы научитесь:

  • строить архитектуры приложений, которые позволяют не снижать скорость разработки по мере развития проекта;
  • писать модульные тесты на Mock-объектах;
  • применять SOLID принципы не только в объектно-ориентированных языках;
  • использовать CI и IoC контейнеры.

Что нужно для старта?

Для старта достаточно знать любой объектно-ориентированный язык программирования: Python, Java, PHP, C++, JavaScript, C# и др.

Игра стоит свеч?

Да, безусловно. Фундаментальные знания на земле не валяются.

Интересно, хочу записаться

Важность принципов проектирования SOLID — BMC Software

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

Принципы SOLID были разработаны Робертом С. Мартином в эссе 2000 года «Принципы проектирования и шаблоны проектирования», хотя аббревиатура была придумана позже Майклом Фезерсом. В своем эссе Мартин признал, что успешное программное обеспечение будет меняться и развиваться. По мере его изменения он становится все более сложным. Мартин предупреждает, что без хороших принципов проектирования программное обеспечение становится жестким, хрупким, неподвижным и вязким. Принципы SOLID были разработаны для борьбы с этими проблемными шаблонами проектирования.

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

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

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

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

Роберт Мартин хорошо обобщает этот принцип, утверждая, что «класс должен иметь одну и только одну причину для изменения». Следование этому принципу означает, что каждый класс делает только одну вещь, и каждый класс или модуль отвечает только за одну часть функциональности программного обеспечения. Проще говоря, каждый класс должен решать только одну задачу.

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

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

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

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

Идея принципа открытости-закрытости состоит в том, что существующие, хорошо протестированные классы нужно модифицировать, когда нужно что-то добавить. Тем не менее, изменение классов может привести к проблемам или ошибкам. Вместо изменения класса вы просто хотите его расширить. Имея в виду эту цель, Мартин резюмирует этот принцип: «Вы должны иметь возможность расширять поведение класса, не изменяя его».

Следование этому принципу необходимо для написания кода, который легко поддерживать и редактировать. Ваш класс соответствует этому принципу, если он:

  1. Открыт для расширения, что означает возможность расширения поведения класса; и
  2. Закрыто для модификации, что означает, что исходный код установлен и не может быть изменен.

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

Принцип замещения Лисков

Из пяти принципов SOLID принцип замещения Лисков, пожалуй, труднее всего понять. В широком смысле этот принцип просто требует, чтобы каждый производный класс был взаимозаменяемым для своего родительского класса. Принцип назван в честь Барбары Лисков, которая в 1987 году ввела эту концепцию поведенческого подтипа. Сама Лисков объясняет принцип, говоря:

Здесь требуется что-то вроде следующего свойства подстановки: если для каждого объекта O1 типа S существует объект O2 типа T такой, что для всех программ P, определенных в терминах T, поведение P не меняется, когда O1 заменяется на O2, тогда S является подтипом T.

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

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

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

Общая идея принципа разделения интерфейсов заключается в том, что лучше иметь много меньших интерфейсов, чем несколько больших. Мартин объясняет этот принцип, советуя: «Создавайте детализированные интерфейсы, ориентированные на клиента. Клиентов не следует заставлять реализовывать интерфейсы, которые они не используют».

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

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

Этот принцип предлагает способ разделения программных модулей. Проще говоря, принцип инверсии зависимостей означает, что разработчики должны «зависеть от абстракций, а не от конкретики». Далее Мартин объясняет этот принцип, утверждая, что «модули высокого уровня не должны зависеть от модулей низкого уровня. Оба должны зависеть от абстракций». Далее, «абстракции не должны зависеть от деталей. Детали должны зависеть от абстракций».

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

Заключение

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

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

Эти сообщения являются моими собственными и не обязательно отражают позицию, стратегию или мнение BMC.

Видите ошибку или есть предложение? Пожалуйста, сообщите нам об этом по электронной почте [email protected]

Принципы S.O.L.I.D в картинках | автор Угонна Тельма | Backticks & Tildes

*Все иллюстрации в этой статье сделаны Ugonna Thelma

Если вы знакомы с объектно-ориентированным программированием, то вы, вероятно, слышали о принципах SOLID .

Эти пять принципов разработки программного обеспечения являются рекомендациями, которым необходимо следовать при создании программного обеспечения, чтобы его было легче масштабировать и поддерживать. Их сделал популярным инженер-программист Роберт С. Мартин.

В Интернете так много замечательных статей о SOLID , но я редко вижу примеры с картинками. Это немного усложняет визуальным ученикам, таким как я, учиться, оставаясь вовлеченным.

Итак, основная цель этой статьи — лучше понять эти принципы, используя иллюстрации и подчеркивая цель каждого принципа.

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

Чтобы упростить понимание, я буду использовать слово «Класс » , но обратите внимание, что в этой статье оно также может относиться к функции , методу или модулю .

Обновление*
Я получил несколько комментариев об открытии и закрытии в этой статье, нарушающем принцип единой ответственности. Обратите внимание, что цель этой статьи — объяснить каждый из этих принципов независимо от других.

Кроме того, обязанности (или роли) отличаются от действий. В SRP я использовал «Я рисую», в Open-Closed — «Я умею рисовать».

Это важно отметить, поскольку для выполнения обязанности (или роли) может быть выполнено несколько действий. У класса должна быть одна ответственность (SRP), но его функциональность, которая выполняет эту ответственность, должна быть открыта для расширения (OCP).

Теперь начнем!

S — Единая ответственность

Класс должен иметь единую ответственность

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

Цель

Этот принцип направлен на разделение поведения, чтобы, если в результате вашего изменения возникнут ошибки, это не повлияло на другие несвязанные поведения.

O — Открытый-Закрытый

Классы должны быть открыты для расширения, но закрыты для модификации

Изменение текущего поведения класса повлияет на все системы, использующие этот класс.

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

Цель

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

Л Лисков Замена

Если S является подтипом T, то объекты типа T в программе могут быть заменены объектами типа S без изменения каких-либо желаемых свойств этой программы.

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

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

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

На рисунке показано, что родительский класс доставляет кофе (это может быть кофе любого типа). Для класса ребенок допустимо доставлять капучино, поскольку это особый вид кофе, но НЕЛЬЗЯ доставлять воду.

Если дочерний класс не соответствует этим требованиям, значит, дочерний класс полностью изменен и нарушает этот принцип.

Цель

Этот принцип направлен на обеспечение согласованности, чтобы родительский класс или его дочерний класс можно было использовать одинаково без каких-либо ошибок.

I Разделение интерфейса

Клиенты не должны зависеть от методов, которые они не используют.

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

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

Цель

Этот принцип направлен на разделение набора действий на более мелкие наборы, чтобы класс выполнял ТОЛЬКО тот набор действий, который ему требуется.

D Инверсия зависимостей

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

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

Во-первых, давайте более просто определим используемые здесь термины

Модуль высокого уровня (или класс) : Класс, который выполняет действие с инструментом.

Низкоуровневый модуль (или класс) : Инструмент, необходимый для выполнения действия

Абстракция : Представляет интерфейс, соединяющий два класса.

Детали : Как работает инструмент

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

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

Цель

Этот принцип направлен на уменьшение зависимости высокоуровневого класса от низкоуровневого класса путем введения интерфейса.

This entry was posted in Популярное