Суть принципов S.O.L.I.D в картинках
Маленький дисклеймер
Статья написана для ИТ-специалистов самого начального уровня, но все же рассчитана на читателей, знакомых с объектно-ориентированным подходом к разработке программ. Если вы еще не успели познакомиться с этим, очень советую обратиться к ссылке выше. После этого обязательно возвращайтесь к прочтению!
Вы, вероятно, уже слышали про SOLID. А что если нет?
SOLID - это пять принципов разработки, которые представляют собой рекомендации, следуя которым вы серьезно упростите себе жизнь при масштабировании и сопровождении своих проектов. Они были популяризированы инженером-программистом Робертом С. Мартином.
Почему здорово, если вы понимаете SOLID?
Это действительно полезные принципы, которые помогают создавать большие и сложные проекты, не превращая их в неуправляемую кучу кода. К тому же про знание этих принципов могут спросить на каждом первом собеседовании практически на любую позицию в ИТ-сфере. Во время собеседований я часто встречаю людей, которые множество раз перечитывали эти принципы, но не могут толком объяснить их смысл и пользу в реальной жизни.
Именно поэтому основная цель этой статьи — лучше понять все 5 принципов, используя иллюстрации и акцентируя внимание на цели каждого из них.
Итак, Принципы SOLID
S — Single Responsibility
Класс должен иметь единственную ответственность.
Для простоты используется слово "класс", но учтите, что в контексте этой статьи - это также может относиться к функции, методу или модулю.
Смысл
Принцип означает, что поведение программы нужно разделять на независимые части. Тогда, если при изменениях возникнут ошибки, они не повлияют на другие, не связанные с ними части.
Смотрим на иллюстрацию
Слева — неправильный подход: один кот выполняет сразу всё — он и повар, и садовник, и водитель, и маляр. Такой код сложно поддерживать: если одна из ролей изменится, придётся переписывать кота целиком. Это нарушает принцип единственной ответственности.
Справа — правильный подход: каждый кот отвечает только за одну задачу. Один — повар, другой — садовник, третий — водитель. Такой код легко поддерживать, тестировать и изменять — потому что изменения в одной ответственности не затрагивают остальные.
O — Open-Closed
Классы должны быть открыты для расширения, но закрыты для изменения.
Смысл
Этот принцип означает, что поведение класса можно добавлять или расширять, но не менять то, что уже работает. Это помогает избежать ошибок там, где этот класс уже используется.
Смотрим на иллюстрацию
На левой стороне:
- Рыжий кот умеет только резать.
- Чтобы он ещё и красил, приходится менять существующий код.
- Это нарушает принцип: мы модифицируем кота, а не расширяем.
На правой стороне:
- Рыжий кот всё так же умеет резать.
- Добавляем нового работника-кота, который знает, как красить.
- Рыжий кот теперь просто расширяет свои возможности, не меняя себя.
- Всё гибко и безопасно.
L — Подстановка Лисков (Liskov Substitution)
Если S — подтип T, тогда объекты типа T в программе могут быть заменены объектами типа S без изменения желаемых свойств этой программы.
Смысл
Этот принцип нужен для того, чтобы родительский и дочерний классы можно было использовать одинаково — и при этом всё работало без ошибок.
Смотрим на иллюстрацию
На картинке показано, что родительский класс выдаёт кофе (любой его вид). Это нормально, если дочерний класс выдаёт капучино — это тоже кофе, но неправильно, если он выдаёт воду.
Если дочерний класс работает по-другому и не поддерживает поведение родительского, — это нарушает принцип.
Когда дочерний класс не может делать то же, что и родительский класс, это может вызвать ошибки.
Дочерний класс должен правильно реагировать на те же запросы и давать такой же результат — или результат того же типа.
I — Принцип разделения интерфейса (Interface Segregation)
Клиенты не должны зависеть от методов, которые они не используют.
Смысл
Этот принцип нужен для того, чтобы разделить обязанности на более мелкие части — чтобы каждый класс выполнял только те действия, которые ему действительно нужны.
Смотрим на иллюстрацию
Слева:
Задания общие для всех котов: "сказать мяу" и "шевелить усами". Но один кот грустно говорит: «Упс! Но у меня нет усов».
Это значит, что его заставляют выполнять то, что он физически не может — ему дали интерфейс с лишними обязанностями.
Справа:
Задания разделили: одни коты умеют «мяукать», другие — «шевелить усами».Теперь каждый выполняет то, что умеет. Все довольны. 😺
Если класс заставляют выполнять действия, которые ему не нужны, это усложняет код и может привести к ошибкам — особенно если класс не умеет делать эти действия.
Класс должен делать только то, что связано с его задачей.Всё остальное лучше либо удалить, либо перенести в другое место — если это может пригодиться другому классу.
D — Принцип инверсии зависимостей (Dependency Inversion)
- Модули высокого уровня не должны зависеть от модулей низкого уровня. Оба должны зависеть от абстракции.
- Абстракции не должны зависеть от деталей. Детали должны зависеть от абстракций.
Смысл
Этот принцип направлен на снижение зависимости высокоуровневого класса от низкоуровневого путём введения интерфейса.
Смотрим на иллюстрацию
На картинке два кота:
- Оранжевый кот говорит: "Я режу пиццу своей рукой-пиццарезкой". Он напрямую зависит от конкретного инструмента — его код "жёстко привязан" к реализации. Если инструмент сломается или поменяется — кот ничего не сможет сделать. Это плохая архитектура.
- Чёрно-белый кот говорит: "Я режу пиццу любым инструментом, который мне дадут". Он не зависит от конкретной реализации, а работает через абстракцию — интерфейс "инструмент для нарезки". Это правильный подход — инверсия зависимостей.
Если у вас есть класс "Кот", он не должен зависеть от конкретной реализации "пиццарезки". Он должен зависеть от интерфейса "инструмент для резки", а конкретный инструмент уже передавать извне.
Итоги
Мы рассмотрели пять принципов и выделили их цели. Они помогают сделать ваш код гибким, расширяемым и легко тестируемым с минимальными проблемами.
Если у вас есть вопросы или предложения — пишите их в мой telegram-канал. Скоро там будет много интересного и полезного контента.
Надеюсь, что вам понравилась статья. Большое спасибо за прочтение!