что означает буква s в аббревиатуре solid

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

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

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

Расшифровка:

Принцип единственной обязанности / ответственности (single responsibility principle / SRP) обозначает, что каждый объект должен иметь одну обязанность и эта обязанность должна быть полностью инкапсулирована в класс. Все его сервисы должны быть направлены исключительно на обеспечение этой обязанности. Подробнее про SRP.

Принцип открытости / закрытости (open-closed principle / OCP) декларирует, что программные сущности (классы, модули, функции и т. п.) должны быть открыты для расширения, но закрыты для изменения. Это означает, что эти сущности могут менять свое поведение без изменения их исходного кода. Подробнее про OCP.

Принцип подстановки Барбары Лисков (Liskov substitution principle / LSP) в формулировке Роберта Мартина: «функции, которые используют базовый тип, должны иметь возможность использовать подтипы базового типа не зная об этом». Подробнее про LSP.

Принцип разделения интерфейса (interface segregation principle / ISP) в формулировке Роберта Мартина: «клиенты не должны зависеть от методов, которые они не используют». Принцип разделения интерфейсов говорит о том, что слишком «толстые» интерфейсы необходимо разделять на более маленькие и специфические, чтобы клиенты маленьких интерфейсов знали только о методах, которые необходимы им в работе. В итоге, при изменении метода интерфейса не должны меняться клиенты, которые этот метод не используют. Подробнее про ISP.

Принцип инверсии зависимостей (dependency inversion principle / DIP) — модули верхних уровней не должны зависеть от модулей нижних уровней, а оба типа модулей должны зависеть от абстракций; сами абстракции не должны зависеть от деталей, а вот детали должны зависеть от абстракций. Подробнее про DIP.

Источник

SOLID принципы. Рефакторинг

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

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

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

Содержание:

Рефакторинг

В литературе достаточно подробно описаны методы рефакторинга [2, 3, 4], зачастую ими являются весьма нехитрые приемы [2], например:

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

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

Рефакторинг должен проводиться постоянно, даже во время изучения кода. Однако он выделяется в качестве отдельного этапа TDD (Test Driven Development, разработки через тестирование) [5].

Даже у опытных программистов нередко бывает предчувствие, что в программе что-то не так, но не удается определить что именно. Фаулер замечательным образом систематизировал методы рефакторинга, а также отметил признаки плохого кода — так называемые «запахи» [2], однако более фундаментальными для объектно-ориентированного подхода являются принципы SOLID.

Принципы чистого кода (SOLID)

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

LSP — Liskov Substitution Principle

Принцип подстановки изначально сформулирован Барбарой Лисков и регламентирует правильное использование механизма наследования. Выделяются некоторый базовый тип, его подтип (класс-наследник). Согласно принципу LSP, программы должны быть написаны таким образом, чтобы в любом месте вместо базового типа мог быть подставлен подтип. Это означает, что классы наследники должны реализовывать интерфейс согласованно с интерфейсом базового класса.

В качестве примера рассмотрим классы геометрических фигур — точка, окружность, сфера.

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

что означает буква s в аббревиатуре solid. Смотреть фото что означает буква s в аббревиатуре solid. Смотреть картинку что означает буква s в аббревиатуре solid. Картинка про что означает буква s в аббревиатуре solid. Фото что означает буква s в аббревиатуре solidLiskov Substitution Principle example

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

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

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

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

Таким образом, принцип подстановки Лисков требует использования открытого наследования лишь для реализации отношения «является разновидностью». На примере показано, что мы не можем установить факт нарушения принципа LSP до тех пор, пока не узнаем как именно будут использоваться наши классы.

DIP — Dependency Inversion Principle

В любой объектно-ориентированной программе существуют зависимости (связи, отношения) между классами. Очевидно, что с ростом количества и силы зависимостей программа становится менее гибкой. Принцип инверсии зависимостей направлен на повышение гибкости программы за счет ослабления связности классов. Ряд источников утверждает, что суть DIP заключается в замене композиции агрегацией, мы рассмотрим это более детально.

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

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

Допустим, мы разработали класс TextReceiver, который принимает по какому-либо каналу связи текст и расшифровывает его. При этом TextReceiver реализуется посредством класса TextDecription, ответственного за расшифровку текста, в связи с этим мы могли бы использовать композицию (верхняя часть рисунка):

что означает буква s в аббревиатуре solid. Смотреть фото что означает буква s в аббревиатуре solid. Смотреть картинку что означает буква s в аббревиатуре solid. Картинка про что означает буква s в аббревиатуре solid. Фото что означает буква s в аббревиатуре solidStrategy pattern example

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

Само по себе использование агрегации вместо композиции решило бы не все проблемы, т.к. новый класс должен был бы наследовать TextDecription, но наследование нарушало бы принцип подстановки Лисков, ведь алгоритм шифрования DES не является разновидностью алгоритма XOR. Чтобы оба принципа были соблюдены — необходимо создавать зависимость от абстрактного класса.

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

Подобная замена композиции агрегацией лежит в основе шаблона проектирования стратегия (Strategy) [8, 11], однако принцип DIP является более общим. Согласно формулировке принципа инверсии зависимостей от Роберта Мартина:

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

что означает буква s в аббревиатуре solid. Смотреть фото что означает буква s в аббревиатуре solid. Смотреть картинку что означает буква s в аббревиатуре solid. Картинка про что означает буква s в аббревиатуре solid. Фото что означает буква s в аббревиатуре solidDependency Inversion Principle example

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

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

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

OCP — Open/Closed principle

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

Открытым называется то, что можно менять. Закрытое изменять нельзя. Существуют различные подходы к понимаю того, каким образом класс должен закрываться — вплоть до требования распространять закрытые модули в скомпилированном виде, но обычно «закрытие» является чисто административным решением.

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

Очень важным требованием принципа открытости/закрытости является сохранение устойчивости интерфейса к расширению системы. Второй пример к принципу DIP иллюстрирует эту проблему: до тех пор, пока класс Person содержал отдельный метод для каждого типа артефакта — его интерфейс нельзя было назвать устойчивым к изменениям. Для решения проблемы мы могли бы создать абстракцию — базовый класс для всех артефактов и добавить в класс Person метод, принимающий эту абстракцию. Новый метод должен выполнять какие-либо конкретные действия в зависимости от типа, при добавлении нового вида артефакта — изменения коснутся лишь реализации этого метода, значит интерфейс можно считать стабильным.

SRP — Single Responsibility Principle

Роберт Мартин выделяет правило одной операции, заключающееся в том, что каждая функция должна решать всегда лишь одну задачу [3]. Принцип единой обязанности — это тоже самое правило, распространенное на класс/модуль.

Фаулер описывает принцип SRP через понятие зоны ответственности [2], под которой он имеет ввиду некоторый контекст в котором работает класс или отдельная функция. Внесения изменений в зону ответственности может повлечь необходимость изменения нашего класса. Класс каким либо образом изменяет свою зону ответственности — это является его обязанностью. Если принцип SRP не нарушается, то каждый класс имеет единственную обязанность, а значит — единственную зону ответственности и единственную причину для изменения. В связи с этим, Фаулер считает необходимость частого внесения изменений в класс «запахом» нарушения принципа единой обязанности.

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

ISP — Interface Segregation Principle

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

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

что означает буква s в аббревиатуре solid. Смотреть фото что означает буква s в аббревиатуре solid. Смотреть картинку что означает буква s в аббревиатуре solid. Картинка про что означает буква s в аббревиатуре solid. Фото что означает буква s в аббревиатуре solidInterface Segregation Principle example

В верхней части диаграммы приведен класс автомобиля. Клиенты могут смотреть на него по-разному, например инспектор ГИБДД видит лишь номер двигателя и скорость, а жена водителя — бардачок и магнитолу. Мы не можем разделить класс на несколько частей, т.к. водителю нужно отслеживать текущую скорость (как инспектору) и хранить в бардачке документы (как это делает жена). Тем не менее, класс может выступать в разных ролях.

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

Заключение и литература по теме

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

В двух фирмах из четырех, где я работал, менеджеры были именно такими — где-то удавалось убедить их обманом в необходимости рефакторинга под предлогом внедрения новых фич, но не везде. Один проект был начат с чистого листа через 4 года разработки. Если в ваши менеджеры ведут себя таким образом, а сроки сдачи всегда «вчера» — скорее всего вам не пригодятся знания по рефакторингу, SOLID, да и любая другая информация для развития профессиональных качеств программиста.

Источник

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

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

Что такое SOLID?

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

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

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

The S ingle Responsibility Principle (SRP) — Принцип единственной ответственности

Существует лишь одна причина, приводящая к изменению объекта.

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

The O pen Closed Principle (OCP) — Принцип открытости/закрытости

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

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

The L iskov Substitution Principle (LSP) — Принцип подстановки Лисков

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

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

The I nterface Segregation Principle (ISP) — Принцип разделения интерфейса

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

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

The D ependency Inversion Principle (DIP) — Принцип инверсии зависимости

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

Под этой достаточно большой формулировкой имеется ввиду следующее (разберем каждое предложение по очереди):

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

Рекомендую ознакомиться с отдельной статье посвященной этой теме Инверсия управления и Внедрение зависимостей (IoС & DI)

Заключение

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

Примеры использования данного принципа в языке программирования C# вы сможете найти в статье Принципы SOLID C#. А также подписывайтесь на группу ВКонтакте, Telegram и YouTube-канал. Там еще больше полезного и интересного для программистов.

Источник

Принципы SOLID, о которых должен знать каждый разработчик

что означает буква s в аббревиатуре solid. Смотреть фото что означает буква s в аббревиатуре solid. Смотреть картинку что означает буква s в аббревиатуре solid. Картинка про что означает буква s в аббревиатуре solid. Фото что означает буква s в аббревиатуре solid

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

Что такое SOLID?

Вот как расшифровывается акроним SOLID:

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

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

«Одно поручение. Всего одно.» — Локи говорит Скурджу в фильме «Тор: Рагнарёк».
Каждый класс должен решать лишь одну задачу.

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

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

Например, рассмотрим этот код:

что означает буква s в аббревиатуре solid. Смотреть фото что означает буква s в аббревиатуре solid. Смотреть картинку что означает буква s в аббревиатуре solid. Картинка про что означает буква s в аббревиатуре solid. Фото что означает буква s в аббревиатуре solid

Как такая структура класса может привести к проблемам?

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

Для того чтобы привести вышеприведённый код в соответствие с принципом единственной ответственности, создадим ещё один класс, единственной задачей которого является работа с хранилищем, в частности — сохранение в нём объектов класса Animal :

что означает буква s в аббревиатуре solid. Смотреть фото что означает буква s в аббревиатуре solid. Смотреть картинку что означает буква s в аббревиатуре solid. Картинка про что означает буква s в аббревиатуре solid. Фото что означает буква s в аббревиатуре solid

Вот что по этому поводу говорит Стив Фентон: «Проектируя классы, мы должны стремиться к тому, чтобы объединять родственные компоненты, то есть такие, изменения в которых происходят по одним и тем же причинам. Нам следует стараться разделять компоненты, изменения в которых вызывают различные причины».

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

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

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

что означает буква s в аббревиатуре solid. Смотреть фото что означает буква s в аббревиатуре solid. Смотреть картинку что означает буква s в аббревиатуре solid. Картинка про что означает буква s в аббревиатуре solid. Фото что означает буква s в аббревиатуре solid

что означает буква s в аббревиатуре solid. Смотреть фото что означает буква s в аббревиатуре solid. Смотреть картинку что означает буква s в аббревиатуре solid. Картинка про что означает буква s в аббревиатуре solid. Фото что означает буква s в аббревиатуре solid

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

Добавим в массив новый элемент:

что означает буква s в аббревиатуре solid. Смотреть фото что означает буква s в аббревиатуре solid. Смотреть картинку что означает буква s в аббревиатуре solid. Картинка про что означает буква s в аббревиатуре solid. Фото что означает буква s в аббревиатуре solid

После этого нам придётся поменять код функции AnimalSound :

что означает буква s в аббревиатуре solid. Смотреть фото что означает буква s в аббревиатуре solid. Смотреть картинку что означает буква s в аббревиатуре solid. Картинка про что означает буква s в аббревиатуре solid. Фото что означает буква s в аббревиатуре solid

Как привести функцию AnimalSound в соответствие с принципом открытости-закрытости? Например — так:

что означает буква s в аббревиатуре solid. Смотреть фото что означает буква s в аббревиатуре solid. Смотреть картинку что означает буква s в аббревиатуре solid. Картинка про что означает буква s в аббревиатуре solid. Фото что означает буква s в аббревиатуре solid

Если теперь добавить в массив объект, описывающий новое животное, функцию AnimalSound менять не придётся. Мы привели её в соответствие с принципом открытости-закрытости.

Рассмотрим ещё один пример.

Представим, что у нас есть магазин. Мы даём клиентам скидку в 20%, используя такой класс:

что означает буква s в аббревиатуре solid. Смотреть фото что означает буква s в аббревиатуре solid. Смотреть картинку что означает буква s в аббревиатуре solid. Картинка про что означает буква s в аббревиатуре solid. Фото что означает буква s в аббревиатуре solid

Теперь решено разделить клиентов на две группы. Любимым ( fav ) клиентам даётся скидка в 20%, а VIP-клиентам ( vip ) — удвоенная скидка, то есть — 40%. Для того, чтобы реализовать эту логику, было решено модифицировать класс следующим образом:

что означает буква s в аббревиатуре solid. Смотреть фото что означает буква s в аббревиатуре solid. Смотреть картинку что означает буква s в аббревиатуре solid. Картинка про что означает буква s в аббревиатуре solid. Фото что означает буква s в аббревиатуре solid

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

что означает буква s в аббревиатуре solid. Смотреть фото что означает буква s в аббревиатуре solid. Смотреть картинку что означает буква s в аббревиатуре solid. Картинка про что означает буква s в аббревиатуре solid. Фото что означает буква s в аббревиатуре solid

Если решено дать скидку в 80% «супер-VIP» клиентам, выглядеть это должно так:

что означает буква s в аббревиатуре solid. Смотреть фото что означает буква s в аббревиатуре solid. Смотреть картинку что означает буква s в аббревиатуре solid. Картинка про что означает буква s в аббревиатуре solid. Фото что означает буква s в аббревиатуре solid

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

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

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

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

что означает буква s в аббревиатуре solid. Смотреть фото что означает буква s в аббревиатуре solid. Смотреть картинку что означает буква s в аббревиатуре solid. Картинка про что означает буква s в аббревиатуре solid. Фото что означает буква s в аббревиатуре solid

Функция нарушает принцип подстановки (и принцип открытости-закрытости). Этот код должен знать о типах всех обрабатываемых им объектов и, в зависимости от типа, обращаться к соответствующей функции для подсчёта конечностей конкретного животного. Как результат, при создании нового типа животного функцию придётся переписывать:

что означает буква s в аббревиатуре solid. Смотреть фото что означает буква s в аббревиатуре solid. Смотреть картинку что означает буква s в аббревиатуре solid. Картинка про что означает буква s в аббревиатуре solid. Фото что означает буква s в аббревиатуре solid

Для того чтобы эта функция не нарушала принцип подстановки, преобразуем её с использованием требований, сформулированных Стивом Фентоном. Они заключаются в том, что методы, принимающие или возвращающие значения с типом некоего суперкласса ( Animal в нашем случае) должны также принимать и возвращать значения, типами которых являются его подклассы ( Pigeon ).

Вооружившись этими соображениями мы можем переделать функцию AnimalLegCount :

что означает буква s в аббревиатуре solid. Смотреть фото что означает буква s в аббревиатуре solid. Смотреть картинку что означает буква s в аббревиатуре solid. Картинка про что означает буква s в аббревиатуре solid. Фото что означает буква s в аббревиатуре solid

Теперь в классе Animal должен появиться метод LegCount :

что означает буква s в аббревиатуре solid. Смотреть фото что означает буква s в аббревиатуре solid. Смотреть картинку что означает буква s в аббревиатуре solid. Картинка про что означает буква s в аббревиатуре solid. Фото что означает буква s в аббревиатуре solid

А его подклассам нужно реализовать этот метод:

что означает буква s в аббревиатуре solid. Смотреть фото что означает буква s в аббревиатуре solid. Смотреть картинку что означает буква s в аббревиатуре solid. Картинка про что означает буква s в аббревиатуре solid. Фото что означает буква s в аббревиатуре solid

В результате, например, при обращении к методу LegCount для экземпляра класса Lion производится вызов метода, реализованного в этом классе, и возвращается именно то, что можно ожидать от вызова подобного метода.

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

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

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

Рассмотрим интерфейс Shape :

что означает буква s в аббревиатуре solid. Смотреть фото что означает буква s в аббревиатуре solid. Смотреть картинку что означает буква s в аббревиатуре solid. Картинка про что означает буква s в аббревиатуре solid. Фото что означает буква s в аббревиатуре solid

Он описывает методы для рисования кругов ( drawCircle ), квадратов ( drawSquare ) и прямоугольников ( drawRectangle ). В результате классы, реализующие этот интерфейс и представляющие отдельные геометрические фигуры, такие, как круг (Circle), квадрат (Square) и прямоугольник (Rectangle), должны содержать реализацию всех этих методов. Выглядит это так:

что означает буква s в аббревиатуре solid. Смотреть фото что означает буква s в аббревиатуре solid. Смотреть картинку что означает буква s в аббревиатуре solid. Картинка про что означает буква s в аббревиатуре solid. Фото что означает буква s в аббревиатуре solid

что означает буква s в аббревиатуре solid. Смотреть фото что означает буква s в аббревиатуре solid. Смотреть картинку что означает буква s в аббревиатуре solid. Картинка про что означает буква s в аббревиатуре solid. Фото что означает буква s в аббревиатуре solid

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

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

что означает буква s в аббревиатуре solid. Смотреть фото что означает буква s в аббревиатуре solid. Смотреть картинку что означает буква s в аббревиатуре solid. Картинка про что означает буква s в аббревиатуре solid. Фото что означает буква s в аббревиатуре solid

Теперь интерфейс ICircle используется лишь для рисования кругов, равно как и другие специализированные интерфейсы — для рисования других фигур. Интерфейс Shape может применяться в качестве универсального интерфейса.

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

Объектом зависимости должна быть абстракция, а не что-то конкретное.

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

что означает буква s в аббревиатуре solid. Смотреть фото что означает буква s в аббревиатуре solid. Смотреть картинку что означает буква s в аббревиатуре solid. Картинка про что означает буква s в аббревиатуре solid. Фото что означает буква s в аббревиатуре solid

Здесь класс Http представляет собой высокоуровневый компонент, а XMLHttpService — низкоуровневый. Такая архитектура нарушает пункт A принципа инверсии зависимостей: «Модули верхних уровней не должны зависеть от модулей нижних уровней. Оба типа модулей должны зависеть от абстракций».

Класс Http не должен знать о том, что именно используется для организации сетевого соединения. Поэтому мы создадим интерфейс Connection :

что означает буква s в аббревиатуре solid. Смотреть фото что означает буква s в аббревиатуре solid. Смотреть картинку что означает буква s в аббревиатуре solid. Картинка про что означает буква s в аббревиатуре solid. Фото что означает буква s в аббревиатуре solid

Интерфейс Connection содержит описание метода request и мы передаём классу Http аргумент типа Connection :

что означает буква s в аббревиатуре solid. Смотреть фото что означает буква s в аббревиатуре solid. Смотреть картинку что означает буква s в аббревиатуре solid. Картинка про что означает буква s в аббревиатуре solid. Фото что означает буква s в аббревиатуре solid

Перепишем класс XMLHttpService таким образом, чтобы он реализовывал этот интерфейс:

что означает буква s в аббревиатуре solid. Смотреть фото что означает буква s в аббревиатуре solid. Смотреть картинку что означает буква s в аббревиатуре solid. Картинка про что означает буква s в аббревиатуре solid. Фото что означает буква s в аббревиатуре solid

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

что означает буква s в аббревиатуре solid. Смотреть фото что означает буква s в аббревиатуре solid. Смотреть картинку что означает буква s в аббревиатуре solid. Картинка про что означает буква s в аббревиатуре solid. Фото что означает буква s в аббревиатуре solid

Итоги

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

Еще больше полезной информации для программистов вы найдете на нашем сайте.

Источник

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *