Вам бонус- начислено 1 монета за дневную активность. Сейчас у вас 1 монета

Принцип разработки объектно-ориентированного программного обеспечения SOLID с примерами и комментариями

Лекция



Привет, сегодня поговорим про solid, обещаю рассказать все что знаю. Для того чтобы лучше понимать что такое solid, solid принципы , настоятельно рекомендую прочитать все из категории Объектно-ориентированное программирование ООП.

SOLID это аббревиатура пяти основных принципов дизайна классов в объектно-ориентированном проектировании — Single responsibility, Open-closed, Liskov substitution, Interface segregation и Dependency inversion.

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

  • 1 цель- для чего?
  • 2 и чтобудет если не собллюдать?
  • 3 и как проверить что соблюден?

Описание принципов SOLID

Буква Означает Описание Для чего?
S Single responsibility principle

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

На каждый класс должна быть возложена одна-единственная обязанность.

  • помогает разбивать и декомпозировать задачи по одной на модуль;
  • уменьшает количество модулей, которые надо изменить при изменении требований;
  • ограничивает влияние изменений, помогая контролировать сложность системы.
O Open/closed principle

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

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

  • заставляет проектировать модули так, чтобы они делали только одну вещь и делали ее хорошо;
  • побуждает связывать сущности через абстракции (а не реализацию) там, где могут поменяться бизнес-требования;
  • обращает внимание проектировщиков на места стыка и взаимодействие сущностей;
  • позволяет сократить количество кода, который необходимо менять при изменении бизнес-требований;
  • делает внесение изменений безопасным и относительно дешевым.
L Liskov substitution principle

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

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

  • помогает проектировать систему, опираясь на поведение модулей;
  • вводит ограничения и правила наследования объектов, чтобы их потомки не противоречили базовому поведению;
  • делает поведение модулей последовательным и предсказуемым;
  • помогает избегать дублирования, выделять общую для нескольких модулей функциональность в общий интерфейс;
  • позволяет выявлять при проектировании проблемные абстракции и скрытые связи между сущностями.
I Interface segregation principle

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

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

  • помогает бороться с наследованием или реализацией ненужной функциональности;
  • дает возможность спроектировать модули так, чтобы их затрагивали изменения только тех интерфейсов, которые они действительно реализуют;
  • снижает зацепление модулей;
  • уничтожает наследование ради наследования, поощряет использование композиции;
  • позволяет выявлять более высокие абстракции и находить неочевидные связи между сущностями.
D Dependency inversion principle

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

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

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

История

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

Описание

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

примеры и комментарии

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


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

Что же такое SOLID-принципы? Если верить определению Wikipedia, это:

аббревиатура пяти основных принципов дизайна классов в объектно-ориентированном проектировании — Single responsibility, Open-closed, Liskov substitution, Interface segregation и Dependency inversion.



Таким образом, мы имеем 5 принципов, которые и рассмотрим ниже:

  • Принцип единственной ответственности (Single responsibility)
  • Принцип открытости/закрытости (Open-closed)
  • Принцип подстановки Барбары Лисков (Liskov substitution)
  • Принцип разделения интерфейса (Interface segregation)
  • Принцип инверсии зависимостей (Dependency Invertion)

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


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

Принцип единственной ответственности гласит — «На каждый объект должна быть возложена одна единственная обязанность». Т.е. другими словами — конкретный класс должен решать конкретную задачу — ни больше, ни меньше.
Принцип разработки объектно-ориентированного программного обеспечения SOLID с примерами и комментариями
Рассмотрим следующее описание класса для представления заказа в интернет-магазине:

  Принцип разработки объектно-ориентированного программного обеспечения SOLID с примерами и комментариями


Как можно увидеть, данный класс выполняет операций для 3 различный типов задач: работа с самим заказом(calculateTotalSum, getItems, getItemsCount, addItem, deleteItem), отображение заказа(printOrder, showOrder) и работа с хранилищем данных(load, save, update, delete).
К чему это может привести?
Приводит это к тому, что в случае, если мы хотим внести изменения в методы печати или работы хранилища, мы изменяем сам класс заказа, что может привести к его неработоспособности.
Решить эту проблему стоит разделением данного класса на 3 отдельных класса, каждый из которых будет заниматься своей задачей

Принцип разработки объектно-ориентированного программного обеспечения SOLID с примерами и комментариямиПринцип разработки объектно-ориентированного программного обеспечения SOLID с примерами и комментариями



Теперь каждый класс занимается своей конкретной задачей и для каждого класса есть только 1 причина для его изменения.

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

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

Бизнес-правилами будем называть правила взаимодействия сущностей друг с другом и внешней средой. Под внешней средой будем понимать все, что влияет на программу извне — пользовательский ввод, события, вызов API и т. д.

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

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

Принцип единственной ответственности (Single Responsibility Principle, SRP) означает, что у модуля должна быть только одна причина для изменения. Весь код, который меняется по этой причине, должен быть собран в этом модуле.

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

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

Принцип разработки объектно-ориентированного программного обеспечения SOLID с примерами и комментариями

Смысл принципа — в объединении частей, которые меняются по одной причине, и разделении тех, которые меняются по разным

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

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

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

Принцип открытости/закрытости (Open-closed)


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

Принцип разработки объектно-ориентированного программного обеспечения SOLID с примерами и комментариями

    Принцип разработки объектно-ориентированного программного обеспечения SOLID с примерами и комментариями


В данном случае хранилищем у нас является база данных. например, MySQL. Но вдруг мы захотели подгружать наши данные о заказах, например, через API стороннего сервера, который, допустим, берет данные из 1С. Какие изменения нам надо будет внести? Есть несколько вариантов, например, непосредственно изменить методы класса OrderRepository, но этот не соответствует принципу открытости/закрытости, так как класс закрыт для модификации, да и внесение изменений в уже хорошо работающий класс нежелательно. Значит, можно наследоваться от класса OrderRepository и переопределить все методы, но это решение не самое лучше, так как при добавлении метода в OrderRepository нам придется добавить аналогичные методы во все его наследники. Поэтому для выполнения принципа открытости/закрытости лучше применить следующее решение — создать интерфейc IOrderSource, который будет реализовываться соответствующими классами MySQLOrderSource, ApiOrderSource и так далее.

Интерфейс IOrderSource и его реализация и использование

  Принцип разработки объектно-ориентированного программного обеспечения SOLID с примерами и комментариями



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

Проектируя систему, мы занимаемся моделированием, а значит решаем инженерную задачу. Об этом говорит сайт https://intellect.icu . Мы строим гипотезу о том, каковы отношения между сущностями в этой системе.

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

Основная причина, по которой вносить изменения бывает трудно или дорого — когда небольшое изменение в одной части системы вызывает лавину изменений в других частях. Грубо и утрировано: если в программе для изменения цвета кнопки надо поправить 15 модулей, такая система спроектирована плохо.

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

Принцип открытости-закрытости (Open-Closed Principle, OCP) помогает исключить такую проблему. Согласно ему модули должны быть открыты для расширения, но закрыты для изменения.

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

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

Модули, которые удовлетворяют OCP:

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

Конечно, всегда есть изменения, которые невозможно внести, не изменив код какого-то модуля — никакая система не может быть закрыта на 100%. Поэтому при проектировании важен стратегический подход. Необходимо определить, от каких именно изменений и какие именно модули вы хотите закрыть. Это решение следует принимать опираясь на опыт, а также знания предметной области и пользователей системы.

Нарушение принципа открытости-закрытости приводит к ситуациям, когда изменение в одном модуле вынуждает менять другие, связанные с ним. Это в свою очередь нарушает SRP, потому что весь код, который меняется по какой-то одной причине, должен быть собран в одном модуле. (Разные модули — разные причины для изменения.)

На примере

На схеме ниже объект Client непосредственно связан с объектом Server. Если нам вдруг понадобится, чтобы Client мог работать с разными объектами Server, нам придется поменять его код.

Принцип разработки объектно-ориентированного программного обеспечения SOLID с примерами и комментариями

Структура, нарушающая OCP

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

Принцип разработки объектно-ориентированного программного обеспечения SOLID с примерами и комментариями

Абстракция помогает развязать модули

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

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

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


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

Принцип разработки объектно-ориентированного программного обеспечения SOLID с примерами и комментариями

Пример иерархии прямоугольника и квадрата и вычислении их площади

    Принцип разработки объектно-ориентированного программного обеспечения SOLID с примерами и комментариями


Очевидно, что такой код явно выполняется не так, как от него этого ждут.
Но в чем проблема? Разве «квадрат» не является «прямоугольником»? Является, но в геометрических понятиях. В понятиях же объектов, квадрат не есть прямоугольник, поскольку поведение объекта «квадрат» не согласуется с поведением объекта «прямоугольник».

Тогда же как решить проблему?
Решение тесно связано с таким понятием как проектирование по контракту. Описание проектирования по контракту может занять не одну статью, поэтому ограничимся особенностями, которые касаются принципа Лисков.
Проектирование по контракту ведет к некоторым ограничениям на то, как контракты могут взаимодействовать с наследованием, а именно:

  • Предусловия не могут быть усилены в подклассе.
  • Постусловия не могут быть ослаблены в подклассе.



«Что еще за пред- и постусловия?» — можете спросите Вы.
Ответ: предусловия – это то, что должно быть выполнено вызывающей стороной перед вызовом метода, постусловия – это то, что, гарантируется вызываемым методом.

Вернемся к нашему примеру и посмотрим, как мы изменили пред- и постусловия.
Предусловия мы никак не использовали при вызове методов установки высоты и ширины, а вот постусловия в классе-наследнике мы изменили и изменили на более слабые, чего по принципу Лисков делать было нельзя.
Ослабили мы их вот почему. Если за постусловие метода setWidth принять (($this->width == $width) && ($this->height == $oldHeight)) ($oldHeight мы присвоили вначале метода setWidth), то это условие не выполняется в дочернем классе и соответственно мы его ослабили и принцип Лисков нарушен.

Поэтому, лучше в рамках ООП и задачи расчета площади фигуры не делать иерархию «квадрат» наследует «прямоугольник», а сделать их как 2 отдельные сущности:

 Принцип разработки объектно-ориентированного программного обеспечения SOLID с примерами и комментариями 



Хороший реальный пример несоблюдения принципа Лискоу и решения, принятого в связи с этим, рассмотрен в книге Роберта Мартина «Быстрая разработка программ» в разделе «Принцип подстановки Лискоу. Реальный пример».

Одна из частых ошибок проектирования программных систем — это попытка полностью скопировать иерархию объектов из реального мира.

Моделируя систему, мы описываем поведение ее компонентов, отношения их друг с другом, а не иерархию. Иерархия — удобный инструмент для моделирования, но иногда она приводит к неправильному описанию поведения.

Классический пример

Представим, что есть класс Rectangle, который описывает прямоугольник:

  Принцип разработки объектно-ориентированного программного обеспечения SOLID с примерами и комментариями

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

 Принцип разработки объектно-ориентированного программного обеспечения SOLID с примерами и комментариями 

Дальше в коде мы используем квадрат. Кажется, что все в порядке:

 Принцип разработки объектно-ориентированного программного обеспечения SOLID с примерами и комментариями

Но если мы используем класс Rectangle в качестве интерфейса, а работаем с конкретным классом Square, то могут возникнуть проблемы:

 Принцип разработки объектно-ориентированного программного обеспечения SOLID с примерами и комментариями

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

Математически — да, квадрат все еще прямоугольник, но он ведет себя иначе, чем прямоугольник.

Принцип подстановки Барбары Лисков (Liskov Substitution Principle, LSP) решает эту проблему, вводя ограничения для иерархии объектов.

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

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

Немного удобнее думать об LSP в терминах «абстракция — реализация». Абстрактный класс или интерфейс играют роль базового типа, но вместе с этим — роль контракта на поведение.

  Принцип разработки объектно-ориентированного программного обеспечения SOLID с примерами и комментариями

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

  Принцип разработки объектно-ориентированного программного обеспечения SOLID с примерами и комментариями

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

function cleanup(disposable: Disposable): void {
  disposable.dispose();
}

const interval = new Interval(() => console.log('Hey!'), 1000);
const timer = new Timer(() => alert('Hey!'), 1000);

cleanup(interval);
cleanup(timer);

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

  • предусловия не могут быть усилены в подклассе;
  • постусловия не могут быть ослаблены в подклассе.

Снова пример

В примере с Rectangle и Square последний ослабляет постусловие для методов setWidth и setHeight. Разберем, что это за постусловие.

Если мы работаем с методом setHeight класса Rectangle, то после вызова метода будем наблюдать ситуацию, когда:

const oldHeight = figure.height
figure.setWidth(newWidth)

assert((figure.width === newWidth) && (figure.height === oldHeight))

Но в случае с квадратом это не так. Постусловие — свойства или состояние после выполнения метода — ослабляется:

const oldHeight = figure.height
figure.setWidth(newWidth)

// постусловие ослаблено, абстракция неправильная
assert((figure.width === newWidth))

Из-за этого использовать Rectangle вместо Square без дополнительных проверок или изменения уже существующих компонентов невозможно.

Принцип подстановки Лисков требует использовать общий интерфейс для обоих классов и не наследовать Square от Rectangle.

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

Наследование и композиция

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

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

Например, наследование предполагает проектирование от общего к частному в виде иерархии:

Животные → Млекопитающие → Человек.

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

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

Человек = Скелет + Нервная система + Иммунная система + Сердечно-сосудистая система + ...

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

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

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

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

Принцип разделения интерфейса (Interface segregation)


Данный принцип гласит, что «Много специализированных интерфейсов лучше, чем один универсальный»
Соблюдение этого принципа необходимо для того, чтобы классы-клиенты использующий/реализующий интерфейс знали только о тех методах, которые они используют, что ведет к уменьшению количества неиспользуемого кода.
Принцип разработки объектно-ориентированного программного обеспечения SOLID с примерами и комментариями
Вернемся к примеру с интернет-магазином.
Предположим наши товары могут иметь промокод, скидку, у них есть какая-то цена, состояние и т.д. Если это одежда то для нее устанавливается из какого материала сделана, цвет и размер.
Опишем следующий интерфейс

  Принцип разработки объектно-ориентированного программного обеспечения SOLID с примерами и комментариями



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

Разбиение интерфейса IItem на несколько

  Принцип разработки объектно-ориентированного программного обеспечения SOLID с примерами и комментариями

Однако, проблема возникает не столько из-за ООП как такового, сколько из-за неправильной модели системы.

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

Сущности не должны зависеть от интерфейсов, которые они не используют.

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

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

SoundEmitter потомком класса TimeInterval.

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

SoundEmitter и

Разделение через множественное наследование

Второй вариант предполагает, что TimeInterval и от IntervalSoundEmitter только нужную функциональность.

Принцип разработки объектно-ориентированного программного обеспечения SOLID с примерами и комментариями

Вариант структуры с множественным наследованием

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

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

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

Принцип инверсии зависимостей (Dependency Inversion Principle, DIP) предполагает, что:

  • Высокоуровневые модули не должны зависеть от низкоуровневых; оба типа должны зависеть от абстракций.
  • Абстракции не должны зависеть от деталей, детали должны зависеть от абстракций.

Таким образом DIP помогает снизить зацепление модулей (coupling).

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

Абстракции

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

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

Принцип разработки объектно-ориентированного программного обеспечения SOLID с примерами и комментариями

Модули зависят от конкретных модулей, это увеличивает зацепление

Исправленный вариант вводит прослойку между сущностями в виде абстракций — интерфейсов.

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

Принцип разработки объектно-ориентированного программного обеспечения SOLID с примерами и комментариями

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

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

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

Признаки плохого проекта

  • Закрепощенность: система с трудом поддается изменениям, поскольку любое минимальное изменение вызывает эффект "снежного кома", затрагивающего другие компоненты системы.
  • Неустойчивость: в результате осуществляемых изменений система разрушается в тех местах, которые не имеют прямого отношения к непосредственно изменяемому компоненту.
  • Неподвижность: достаточно трудно разделить систему на компоненты, которые могли бы повторно использоваться в других системах.
  • Вязкость: сделать что-то правильно намного сложнее, чем выполнить какие-либо некорректные действия.
  • Неоправданная сложность: проект включает инфраструктуру, применение которой не влечет непосредственной выгоды.
  • Неопределенность: проект трудно читать и понимать. Недостаточно четко выражено содержимое проекта.


Резюмируя все выше изложенное, можно сделать слудущие выводы что нужно для хорошего проекта

  • Принцип единственной ответственности (Single responsibility)
    «На каждый объект должна быть возложена одна единственная обязанность»
    Для этого проверяем, сколько у нас есть причин для изменения класса — если больше одной, то следует разбить данный класс.
  • Принцип открытости/закрытости (Open-closed)
    «Программные сущности должны быть открыты для расширения, но закрыты для модификации»
    Для этого представляем наш класс как «черный ящик» и смотрим, можем ли в таком случае изменить его поведение.
  • Принцип подстановки Барбары Лисков (Liskov substitution)
    «Объекты в программе могут быть заменены их наследниками без изменения свойств программы»
    Для этого проверяем, не усилили ли мы предусловия и не ослабили ли постусловия. Если это произошло — то принцип не соблюдается
  • Принцип разделения интерфейса (Interface segregation)
    «Много специализированных интерфейсов лучше, чем один универсальный»
    Проверяем, насколько много интерфейс содержит методов и насколько разные функции накладываются на эти методы, и если необходимо — разбиваем интерфейсы.
  • Принцип инверсии зависимостей (Dependency Invertion)
    «Зависимости должны строится относительно абстракций, а не деталей»
    Проверяем, зависят ли классы от каких-то других классов(непосредственно инстанцируют объекты других классов и т.д) и если эта зависимость имеет место, заменяем на зависимость от абстракции.

Эти принципы помогают нам писать лучший код и уменьшать количество ошибок в будущем. Всегда помните: « Время меняется, но принципы не меняются ». Итак, давайте займемся счастливым кодированием.

Вау!! 😲 Ты еще не читал? Это зря!

<p style="box-sizing: border-box; margin: 0px 0px 1rem; color: rgb(0, 0, 0); font-family: -apple-system, BlinkMacSystemFont, " segoe="" ui",="" roboto,="" oxygen,="" ubuntu,="" cantarell,="" "fira="" sans",="" "droid="" "helvetica="" neue",="" sans-serif;="" font-size:="" 16px;"="">

Надеюсь, эта статья про solid, была вам полезна, счастья и удачи в ваших начинаниях! Надеюсь, что теперь ты понял что такое solid, solid принципы и для чего все это нужно, а если не понял, или есть замечания, то не стесняйся, пиши или спрашивай в комментариях, с удовольствием отвечу. Для того чтобы глубже понять настоятельно рекомендую изучить всю информацию из категории Объектно-ориентированное программирование ООП

создано: 2015-01-11
обновлено: 2021-11-21
132556



Рейтиг 9 of 10. count vote: 2
Вы довольны ?:


Поделиться:

Найди готовое или заработай

С нашими удобными сервисами без комиссии*

Как это работает? | Узнать цену?

Найти исполнителя
$0 / весь год.
  • У вас есть задание, но нет времени его делать
  • Вы хотите найти профессионала для выплнения задания
  • Возможно примерение функции гаранта на сделку
  • Приорететная поддержка
  • идеально подходит для студентов, у которых нет времени для решения заданий
Готовое решение
$0 / весь год.
  • Вы можите продать(исполнителем) или купить(заказчиком) готовое решение
  • Вам предоставят готовое решение
  • Будет предоставлено в минимальные сроки т.к. задание уже готовое
  • Вы получите базовую гарантию 8 дней
  • Вы можете заработать на материалах
  • подходит как для студентов так и для преподавателей
Я исполнитель
$0 / весь год.
  • Вы профессионал своего дела
  • У вас есть опыт и желание зарабатывать
  • Вы хотите помочь в решении задач или написании работ
  • Возможно примерение функции гаранта на сделку
  • подходит для опытных студентов так и для преподавателей



Комментарии


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

Объектно-ориентированное программирование ООП

Термины: Объектно-ориентированное программирование ООП