Принципы SOLID
Last updated
Last updated
Термин "SOLID" представляет собой акроним для набора практик проектирования программного кода и построения гибкой и адаптивной программы. Данный термин был введен 15 лет назад известным американским специалистом в области программирования Робертом Мартином
Сам акроним образован по первым буквам названий SOLID-принципов:
Single Responsibility Principle (Принцип единственной обязанности)
Open/Closed Principle (Принцип открытости/закрытости)
Liskov Substitution Principle (Принцип подстановки Лисков)
Interface Segregation Principle (Принцип разделения интерфейсов)
Dependency Inversion Principle (Принцип инверсии зависимостей)
Принцип единственной обязанности (Single Responsibility Principle) можно сформулировать так: У класса должна быть только одна причина для изменения Под обязанностью здесь понимается набор функций, которые выполняют единую задачу. Суть этого принципа заключается в том, что класс должен выполнять одну единственную задачу. Весь функционал класса должен быть целостным, обладать высокой связностью (high cohesion).
Допустим в классе Report написано очень много разных способов вывести репорт пользователю. Если мы поменяем Text на какой-то метод, то нам придется править каждый из методов печати, т.к. они работали напрямую с Text. Это очень долго, да и сам класс получился очень большим, а в более сложных и реальных системах нарушение SRP может окончательно запутать программиста, если он решится что-то поменять в коде. Нарушение этого принципе не столько ограничивает программиста, сколько заставляет его писать лишний код по мере роста проекта, в котором легко запутаться
Проблему бесконечного наращивания и уменьшение его связанности можно решить созданием интерфейса IPrinter, и его реализацией в виде ConsolePrinter и FilePrinter. При применении SRP в начале будет казаться, что мы только усложняет код, и увеличиваем его в размерах, но по мере разработки проекта он не будет так сильно дальше усложнятся и разрастаться, по сравнению с кодом, который был написан без соблюдения SRP
Принцип открытости/закрытости (Open/Closed Principle) можно сформулировать так: Сущности программы должны быть открыты для расширения, но закрыты для изменения. Суть этого принципа состоит в том, что система должна быть построена таким образом, что все ее последующие изменения должны быть реализованы с помощью добавления нового кода, а не изменения уже существующего, за исключением фикса багов и рефакторинга
Принцип подстановки Лисков (Liskov Substitution Principle) представляет собой некоторое руководство по созданию иерархий наследования. В общем случае данный принцип можно сформулировать так: Должна быть возможность вместо базового типа подставить любой его подтип.
Фактически принцип подстановки Лисков помогает четче сформулировать иерархию классов, определить функционал для базовых и производных классов и избежать возможных проблем при применении полиморфизма.
Класс Square перестает быть квадратом, потому что подвергается некорректным изменением под видом обычного прямоугольника, которого наследует. Решение данной ситуации – не наследовать Square от Rectangle, а делать 2 разных класса
Принцип разделения интерфейсов (Interface Segregation Principle) относится к тем случаям, когда классы имеют "жирный интерфейс", то есть слишком раздутый интерфейс, не все методы и свойства которого используются и могут быть востребованы. Таким образом, интерфейс получатся слишком избыточен Принцип разделения интерфейсов можно сформулировать так: Клиенты не должны вынужденно зависеть от методов, которыми не пользуются. При нарушении этого принципа клиент, использующий некоторый интерфейс со всеми его методами, зависит от методов, которыми не пользуется, и поэтому оказывается восприимчив к изменениям в этих методах. В итоге мы приходим к жесткой зависимости между различными частями интерфейса, которые могут быть не связаны при его реализации.
ISP нарушается когда мы оставляем части интерфейса не реализованными. Это говорит нам о том, что интерфейс можно разбить на более мелкие интерфейсы
Принцип инверсии зависимостей (Dependency Inversion Principle) служит для создания слабосвязанных сущностей, которые легко тестировать, модифицировать и обновлять. Этот принцип можно сформулировать следующим образом:
Классы верхнего уровня не должны зависеть от классов нижнего уровня. И те и другие должны зависеть от абстракций. Абстракции не должны зависеть от деталей класса. Детали класса должны зависеть от абстракций.
Класс Book, представляющий книгу, использует для печати класс ConsolePrinter. При подобном определении класс Book зависит от класса ConsolePrinter. Более того мы жестко определили, что печать книгу можно только на консоли с помощью класса ConsolePrinter
Конкретную реализацию можно представить как абстракцию (интерфейс), и уже работать только с ней
Таким образом мы можем реализовывать конкретные классы на основании сделанной абстракции