SOLID принципы были придуманы в начале 2000-х Робертом Мартином. На них строится вся современная разработка программного обеспечения. Принципы были созданы для удобства чтения, поддержки и расширения возможностей уже написанного кода.
S - single responsibility
Принцип единственной ответственности. Класс должен отвечать только за тот функционал, который подразумевает его название. Класс не должен уметь делать все что угодно. Например, вы пишете интернет магазин. Создаёте класс-сервис, который отвечает за всю бизнес логику, добавление и поиск товара, регистрация пользователей, все действия с корзиной. Согласитесь, такой код будет сложно поддерживать, а другим разработчикам сложно будет в нем разобраться. Поэтому класс следует разбить как минимум на 3: SignUpService, ProductService и BasketService.
Теперь в нашем проекте будет соблюдаться первый принцип.
O - open-closed
Принцип открытости-закрытости. Классы должны быть открыты для расширения и закрыты для изменения. В его соблюдении нам поможет наследование классов. Сущность не должна переписываться. Представьте, что ваш класс лежит в библиотеке и вам понадобилось добавить ей еще пару методов. Конечно, переписать и заново его скомпилировать будет трудозатратно.
Конструкции switch case в некоторых случаях подталкивают разработчика нарушить данный принцип. Например нам приходит сообщение и в зависимости от его типа нужно передать его обработчику. Велик соблазн сделать это с помощью switch case, однако при появлении новых типов пакетов придется переписывать код. Поэтому лучше хранить обработчики и с помощью цикла проходить по ним и сравнивать тип сообщения и обработчика и передавать ему сообщение.
L - Liskov substitution principle
Принцип подстановки Барбары Лисков.
Потомки должны иметь возможность использоваться вместо классов-родителей без потери функциональности. Например, есть класс грузовой автомобиль. От него наследуется грузовик с прицепом. По принципу L грузовик с прицепом так же как и простой грузовик может возить товары.
I - interface segregation
Принцип разделения интерфейсов.
Много маленьких интерфейсов лучше, чем один большой. Интерфейс с большим количеством методов содержит много лишнего. Например, у вас есть интерфейс водоплавающей птицы. Там будут методы летать и плавать. Лучше будет разделить этот интерфейс на два. Летающий и плавающий. Такой интерфейс будет намного универсален и удобен в использовании.
Интерфейс не должен навязывать классу лишний функционал, а если в нем очень много методов, то велика вероятность, что вашему классу все они не пригодятся.
D - dependency inversion
Модули верхних уровней не должны зависеть от модулей нижних уровней. Оба типа модулей должны зависеть от абстракций.
Абстракции не должны зависеть от деталей. Детали должны зависеть от абстракций.
Все зависимости строятся на абстракции, а не на конкретной реализации. Классы зависят от интерфейсов, мы можем гибко менять их реализацию и поведение.
Заключение
Принципы достаточно непросты для понимая. Однако знать и уметь их применять на практике очень важно. Ваши модули и программы станут намного более гибкими и масштабируемыми и вы сами будете получать удовольствие от их развития.