SOLID principles

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

S – Single Responsibility Principle (SRP)

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

Т.е. если нужно изменить что-то одно и что-то другое (строго не связанное с первым) и для этого нужно менять код одного класса, то этот класс нарушает SRP.

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

Назначение

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

Видео

O — Open-Closed Principle (OCP)

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

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

Назначение

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

Видео

L — Liskov Substitution Principle (LSP)

Объекты (классы) можно заменить на под-объекты (классы созданные на базе первого класса) при этом программа не должна сломаться.

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

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

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

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

Назначение

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

Видео

I — Interface Segregation Principle (ISP)

Клиент должен знать о методах класса, которые нужны ему и не знать ничего о каких-либо других методах.

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

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

Назначение

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

Видео

D — Dependency Inversion Principle (DIP)

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

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

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

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

Назначение

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

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

Видео

--

Фото были взяты здесь: https://habr.com/ru/company/productivity_inside/blog/505430/