100500-я статья про солид.
Об этом можно писать бесконечно и все равно ничего не ясно.
--
SOLID - это аббревиатура, которая объединяет в себе 5 принципов, способствующих написанию правильного кода (и каждый уважающий себя HR напишет эту аббревиатуру в описание вакансии, хотя не понимает что оно такое).
1). Single Responsibility Principle (Принцип единственной ответственности) - это означает, что каждый класс должен отвечать только за одну задачу. Например, если у вас есть класс "Корзина", он должен отвечать только за добавление и удаление товаров из корзины, но не должен отвечать за оплату или оформление заказа.
Пример принципа единственной ответственности можно привести на основе класса "Пользователь" в системе авторизации. Если мы будем следовать принципу единственной ответственности, то класс "Пользователь" должен заниматься только управлением пользователями, а не каким-то другим функционалом.
Вот пример реализации этого принципа:
В этом примере класс "User" имеет только три метода, которые отвечают за создание, удаление и обновление пользователя в базе данных. Класс не отвечает за другие задачи, такие как проверка пароля или отправка электронной почты, и это позволяет легко понимать и использовать его код.
Если бы мы добавили в класс "User" методы для проверки пароля или отправки электронной почты, это бы нарушило принцип единственной ответственности и сделало класс более сложным для понимания и использования.
2). Open-Closed Principle (Принцип открытости/закрытости) - это означает, что классы должны быть открыты для расширения, но закрыты для изменения. Например, если у вас есть класс "Фигура", вы можете расширить его, добавив новую фигуру, но вы не должны изменять существующий код, чтобы поддерживать новую фигуру.
Принцип открытости/закрытости можно проиллюстрировать на примере класса "Фигура", который имеет методы для вычисления площади и периметра фигуры. Если мы будем следовать принципу открытости/закрытости, то класс "Фигура" должен быть открыт для расширения новыми фигурами, но закрыт для изменения существующего кода.
Вот пример реализации этого принципа:
В этом примере абстрактный класс "Shape" (фигура) определяет методы для вычисления площади и периметра фигуры. Класс "Rectangle" и "Circle" наследуются от абстрактного класса "Shape" и реализуют свои собственные методы для вычисления площади и периметра.
Если нам потребуется добавить новую фигуру, например, "Треугольник", мы можем создать новый класс "Triangle", который также будет наследоваться от абстрактного класса "Shape" и реализовывать свои собственные методы для вычисления площади и периметра, не изменяя при этом код класса "Shape".
Таким образом, мы можем расширять функциональность нашей системы без изменения уже существующего кода.
3). Liskov Substitution Principle (Принцип подстановки Лисков) - это означает, что вы должны использовать наследование только тогда, когда вы можете заменить экземпляр базового класса экземпляром производного класса без нарушения работы программы. Например, если у вас есть класс "Животное" и класс "Собака", то вы можете использовать экземпляры класса "Собака" везде, где ожидается экземпляр класса "Животное".
Принцип подстановки Лисков (Liskov Substitution Principle, LSP) является одним из основных принципов SOLID в объектно-ориентированном программировании. Он утверждает, что подклассы должны быть взаимозаменяемы со своими базовыми классами, т.е. код, написанный для базового класса, должен работать без изменений с объектами подкласса.
Вот пример кода на PHP, демонстрирующий принцип подстановки Лисков:
В этом примере классы Rectangle и Square наследуют класс Shape. Метод printArea принимает объект типа Shape в качестве параметра и выводит его площадь. Объекты класса Square переопределяют методы setWidth и setHeight таким образом, чтобы устанавливать и ширину, и высоту равными переданному значению (это свойственно только для квадрата).
Принцип подстановки Лисков выполняется, потому что объекты Rectangle и Square могут быть использованы вместо объекта Shape без изменения поведения метода printArea.
4). Interface Segregation Principle (Принцип разделения интерфейсов) - это означает, что вы должны создавать интерфейсы, которые содержат только необходимые методы. Например, если у вас есть класс "Работник", который имеет методы "Работать" и "Отдыхать", вы можете разделить интерфейс на "Работающий" и "Отдыхающий", чтобы классы могли реализовывать только нужные методы.
Принцип разделения интерфейсов (Interface Segregation Principle, ISP) является одним из принципов SOLID-подхода к проектированию программного обеспечения. Он утверждает, что клиенты не должны зависеть от методов, которые они не используют.
В PHP пример использования ISP может выглядеть следующим образом:
В данном примере мы имеем два интерфейса: Car и Radio. Интерфейс Car определяет два метода: start() и stop(), которые необходимы для любой машины. Интерфейс Radio определяет три метода: turnOn(), turnOff() и setVolume(), которые могут быть не нужны для всех типов машин.
Класс LuxuryCar реализует оба интерфейса, так как люксовая машина должна иметь как радио, так и двигатель. Класс EconomyCar реализует только интерфейс Car, так как экономичная машина не обязательно должна иметь радио.
Таким образом, использование принципа разделения интерфейсов позволяет создавать более гибкие и расширяемые классы, так как они не зависят от методов, которые они не используют. Это упрощает поддержку кода и повышает его качество.
5). Dependency Inversion Principle (Принцип инверсии зависимостей) - это означает, что классы верхнего уровня не должны зависеть от классов нижнего уровня. Например, если у вас есть класс "Сайт", который зависит от класса "База Данных", вы можете создать абстракцию, которая будет использоваться классом "Сайт", вместо того чтобы он зависел от класса "База Данных" напрямую.
Принцип инверсии зависимостей (Dependency Inversion Principle, DIP) является одним из принципов SOLID-подхода к проектированию программного обеспечения. Он утверждает, что модули верхнего уровня не должны зависеть от модулей нижнего уровня, а оба типа модулей должны зависеть от абстракций.
В PHP пример использования DIP может выглядеть следующим образом:
В данном примере мы имеем интерфейс DatabaseInterface, который определяет два метода: connect() и query(). Классы MysqlDatabase и PostgresDatabase реализуют этот интерфейс и предоставляют соответствующие реализации методов для подключения и выполнения запросов к соответствующим базам данных.
Класс UserManager зависит от интерфейса DatabaseInterface вместо конкретных реализаций баз данных, что позволяет легко заменять одну базу данных на другую, не изменяя код класса UserManager. Это осуществляется за счет инъекции зависимости через конструктор, где объект класса, реализующего интерфейс DatabaseInterface, передается в качестве аргумента.
Таким образом, использование принципа инверсии зависимостей позволяет создавать более гибкие и расширяемые классы, так как они не зависят от конкретных реализаций зависимостей, а только от их абстракций. Это упрощает поддержку кода и повышает его качество.