Принципы SOLID были представлены Робертом Мартином в статье 2000 года «Design Principles and Design Patterns», посвящённой деградации программного обеспечения. Пять принципов SOLID в программировании призваны сделать объектно-ориентированные проекты более понятными, гибкими и удобными в поддержке. Давайте рассмотрим каждый принцип немного подробнее!
- (S) Single Responsibility – никогда не должно быть больше одной причины изменить класс(1). Класс выполняет единственное назначение!
- Нарушение: класс занимается сохранением данных в базой данных, а также отправкой данных на сервер. Решение: Лучше разделить класс на два класса.
- Нарушение в Android: Context – отвечает за множество задач одновременно.
- (O) Open Closed – простая для изменения система должна предусматривать простую возможность изменения ее поведения добавлением нового, но не изменением существующего кода.
- Нарушение: мы изменяем методы класса, вместо того, чтобы наследоваться от него, переопределять и создавать методы.
- Нарушение в Android: ExoPlayer – от одной версии библиотеки к другой, изменялась функциональность MediaSource, под которую клиенты должны были подстраиваться.
- (L) Liskov’s Substitution – объекты в программе можно заменить их наследниками без изменения правильности выполнения программы.
- Нарушение: известная проблема квадрат / прямоугольник, когда квадрат наследуется от прямоугольника. Где у прямоугольника можно менять независимо ширину и высоту, а у квадрата – только всё вместе.
- Нарушение в Android: RecyclerView – переопределяет метод scrollTo и выводит в лог ошибку.
- (I) Interface Segregation – слишком «толстые» интерфейсы необходимо разделять на более мелкие и специфические.
- Нарушение: огромный интерфейс с разными методами. Лучше разделить интерфейс на несколько интерфейсов.
- Нарушение в Android: огромный интерфейс List содержит множество методов, которые клиент может не реализовывать.
- (D) Dependency Inversion – код, реализующий высокоуровневую политику, не должен зависеть от кода, реализующего низкоуровневые детали. Абстракции не должны зависеть от деталей. Детали должны зависеть от абстракций.
- Нарушение: модуль высокого уровня зависит от модуля низкого уровня через конкретный класс, а не через абстракцию. Например, вместо создания интерфейса репозитория, мы используем класс репозитория. Таким образом, более высокий уровень (а это Domain – UseCases и Entities) будет зависеть от реализации Data слоя.
- Нарушение в Android: Context – обычно используем его напрямую везде, а он, в свою очередь, зависит от других сущностей, что усложняет тестирование.
Напоследок:
- Не ссылайтесь на изменчивые конкретные классы. Используйте шаблон Абстрактная фабрика и Фабричный метод.
- Не наследуйте изменчивые конкретные классы. Наследование в языках со статической системой типов является самым строгим и жестким видом отношений в исходном коде.
- Не переопределяйте конкретные функции, реализуйте абстрактные функции.
- Никогда не ссылайтесь на имена конкретных и изменчивых сущностей.
(1) – слово «класс» может обозначать не только ООП класс, но и объединения функций и данных в группы. Любая программная система имеет такие объединения, например, это может быть «модуль».