SOLIDно знать…
Такие вещи как SOLID не редко можно услышать в кулуарных разговорах или что еще чаще на собеседовании. Но отчасти не зная в точности SOLID, каждый программист бессознательно, но придерживается данных принципов, когда есть на то время)) Но почему нам как программистам важно знать в точности смысл таких аббривиатур или, если вам угодно, тех или иных смыслов из нашей профессии. А всё просто — это как минимум солидно, или вернее сказать — не знать этого не солидно. (подробнее об этом в P.S.)
В частности о SOLID много что уже есть на хабре, но моя статья это больше о связи между теории с реальной жизнью. В прошлой статье я попытался связать паттерны в умах людей с кодом с которым каждый, как Java Developer, работает деть ото дня. В данной статье же я уже сами принципы SOLID попытаюсь связать с паттернами, а вернее с некоторыми из них, что бы одно с другим в вашей голове вошло в согласие, и было не раздельно, так как я считаю что для них нет ничего ближе друг другу, да и вообще, паттерн есть принцип и обратное. SOLID это теория которая на практике чаще реализуется в виде паттернов. Эта статья в некотором роде перекрестный бой между паттернами и SOLID принципами.
SRP
Single Responsibility Principe — Принцип единой ответственности.
Каждый объект должен стремится к одной зоне ответственности и к одной причине для существования или если проще говоря: каждый класс должен иметь одну обязанность и, следовательно, одну причину для изменения.
Ну, по моему мнению, это один из самых главных принципов, заключенных в SOLID. Его разумное применение избавляет от многих головных проблем, те кто совместно работает над классами-монстрами и ломает голову при конфликтах — поймут меня, но статья не об этом.
Стратегия. Выносим реализацию определенного алгоритма в отдельный класс и это нам дает:
Наш класс и непосредственно сам алгоритм имеют свою зону ответственности и не мешают друг другу +1 SRP
Если в алгоритмах нужно что-то поменять, то у нас нет причин изменять сам класс родитель. И в том и в другом случае это плюс к одной причине для изменения. +1 SRP
Фасад. Что бы ваш класс не зависел от какой-то внешней сложной системы, создайте просто фасад для этой системы, что это нам дает:
Наш класс и непосредственно сама работа с системой имею свою зону ответственности и не мешают друг другу. +1 SRP
Если в работе с системой что-то нужно поменять, то у нас нет причин изменять сам класс родитель. И в том и в другом случае это плюс к одной причине для изменения. +1 SRP
DDD. Разбивает всю модель предметной области (домен) на поддомены. У каждого поддомена своя модель данных, область действия которой принято называть ограниченным контекстом +1 SRP
Database per service. Каждый сервис имеет свою базу данных для работы, и каждая база имеет лишь один сервис для работы которой он может быть изменен +1 SRP
CQRS. Если в простой форме, то теперь у нас логика записи и чтения данных раздельно существуют и имеют разную область ответственности.
OCP
Open-closed Principle — Принцип открытости-закрытости.
Программные сущности (классы, модули, функции и т.п.) должны быть открыты для расширения, но закрыты для изменения.
Стратегия. Выносим реализацию определенного алгоритма в отдельный класс и это нам дает: теперь нет необходимости лезть в родительский класс, для добавления новой логики. +1 OCP
Адаптер. Данный паттерн предназначен для организации использовании функционала объекта, недоступного или нежелательного для модификации, и у меня такое ощущение, что данный паттерн именно что и создан для решения проблемы отсутствия OCP в коде. Пусть система для которой мы пишем адаптер и не стремилась быть гибкой для всех, но мы расширим ее возможности без потребности лезть во внутрь. +1 OCP
Декоратор. Добавляем дополнительное поведение объекту, не меняя внутренности других декораторов и самого класса. +1 OCP
Вообще стоит отметить что паттернов которые помогают нам придерживаться данного принципа вагон и маленькая тележка: Шаблонный метод, Мост и тд. +10 OCP
LSP
Liskov Substitution Principle — Принцип подстановки Барбары Лисков
Объекты в программе должны быть заменяемыми на экземпляры их подтипов без изменения правильности выполнения программы.
Шаблонный метод. Было странно не упомянуть данный паттерн при разборе данного принципа, так как и данный паттерн и данный принцип на всю используют возможность полиморфизма.
Декоратор. При реализации данного паттерна необходимо так же придерживаться данного принципа, так каждый подключаемый декоратор подразумевает добавление дополнительного поведения объекту, а не изменение его логики до неузнаваемости, так что трудно будет отследить где-же все пошло не так как надо +1 LSP
Стоит отметить что конкретно со сложностью реализации данного принципа в жизнь, излишней сложность или, в конце концов, халтурным отношением создателей тех или иных библиотек, мы в свою очередь сами как Java разработчики часто встречаемся при работе с исключениями связанными с «беспринципностью» разработчиков…
UnsupportedOperationException
— тогда когда мы получаем к примеру список и ни в чем не подозревая, пытаемся добавить в него новый элемент. Да, многие методы реализации интерфейсаList
, который возвращается, к примеру, тем жеList.of(...)
выбрасывают данное исключениеPSQLException
— когда мы к примеру вызываем методexecute (String sql)
у нашегоStatement
, а он в свою очередь является реализациейPreapredStatement
postgres драйвера.
Но стоит отметить что примеры выше, это не совсем плохо, нет, это более или менее оправдано, нарушение LSP более критично тогда, когда мы не просто сталкиваемся с исключением в исходниках или в рантайме и решаем проблемы, а тогда когда мы не встречаем сразу явных изменений логики в методах контракта реализованные некоторым классом, но он в свою очередь их имеет, и проблема уже тут в том, что разработчик данного кода нас заранее не оповестил об этом. -1 LSP
ISP
Interface Segregation Principle — Принцип разделения интерфейса
Клиенты не должны зависеть от методов, которые они не используют, в общем, это про правильное разделение интерфейсов.
Backends for frontends. Кроме всех остальных возможностей, данный архитектурный паттерн позволяет нам собрать запрос для определенного клиента в необходимом для него виде, тем самым мы можем не делать общее api для всех клиентов, путая их или ограничивая в чем-то, а реализовать свой вариант для каждого, разделив все по необходимости +1 ISP
DIP
Dependency inversion principle — Принцип инверсии зависимостей
Модули верхних уровней не должны зависеть от модулей нижних уровней. Оба типа модулей должны зависеть от абстракций. То есть, абстракции не должны зависеть от деталей, детали должны зависеть от абстракций.
Создать абстракции это одно, но непосредственное конкретная инициализация объекта это другое, то есть IoC, и здесь так же мы не должны зависеть от деталей, то есть забыли про ключевое слово new
IoC. Inversion of Control — это некий абстрактный принцип, набор рекомендаций для написания слабо связанного кода. Суть которого в том, что каждый компонент системы должен быть как можно более изолированным от других, не полагаясь в своей работе на детали конкретной реализации других компонентов. +1 DIP
Фабричный метод. Создание того или иного объекта выносится за пределы класса, тем самым освобождая его от той или иной реализации +1 DIP
Фасад. Переносим логику работы некоторой системы в соответствующий класс и получаем — наш модуль не зависит от деталей, то есть не связан с сложностью той или иной системы, и если зависит то только от абстракции фасада +1 DIP
Observer. Реализуем у класса механизм, который позволяет объекту этого класса получать оповещения об изменении состояния других объектов и тем самым делаем связь между объектами слабосвязанной и менее зависим от других классов (абстракций) впринципе +1 DIP
P.S.
Почему же знать такое солидно?
Был раз я гулял по одному красивому европейскому городу, я любовался им впервые, но в какой-то момент я заметил одного человека, белокурого и с ясными голубыми глазами, который явно с неприкрытым удивлением наблюдал меня, а в частности, его привлекли мои излияния всему меня окружающему, а точнее, ну как будет видно далее, их форма. Это продолжалось недолгое время и он в какой-то момент оказался рядом и поздоровавшись со мной на английском, спросил у меня: родом ли я из России. Честно говоря, я немного замешкался, так как мой английский что тогда, что и сейчас, доставляет мне много неудобств в живом разговоре, но более-менее столь простой вопрос я смог расшифровать и ответил или даже кивнул в знак согласия. Он же улыбнулся и ответил: мол, и я тоже, и более того он сказал, что он русский. После этих слов (конечно же, мне пришлось немного подумать) я тоже в ответ улыбнулся и был рад, надеясь, что хоть некоторую часть слов я смогу себе позволить на русском, и немного подумав, спросил уже на русском: аа, как дела ? Нууу… тут уже с другой стороны ответ заставил себя подождать, но все же через секунды две человек ответил что не понял меня от слова совсем и вообще не говорит по-русски. Я немного помялся (мне нужно было тоже понять, что он не понял меня), и я переформулировал свой вопрос на английском и собеседник в свою очередь ответил: мол, что не очень, я же любезно поинтересовался что случилось, а он ответил что-то вроде — не задался день с самого начала. Я сочувствующим взглядом ответил что мне жаль и что все наладится (это я умею) и после этого я решил более не продолжать разговор так как нам уже не о чем было говорить, что собственно тогда я и сделал, пожав ему руку и быстро удалившись.
К чему же это я, вы спросите?! Вернемся к тому мужчине, думаете почему я не хотел с ним более стоять или продолжить знакомство, хотя его радостное лицо при упоминании что я из России меня обрадовало ?! Я общительный малый, да и мне было бы приятно услышать родную речь, но… Оказалось что человек за всю свою осознанную жизнь не удосужился хоть немного погрузится в родной язык (хоть и смог среди толпы меня услышать) перед тем как кричать: я из России… и тд. Вы должны меня понять, я не имею ничего против его национальной идентичности и не говорю что он не является тем кем он представляется, нооо… это просто навсего не солидно, ребята. Разве он не знает что такое how are you? Нет, он знает как поинтересоваться у человека о его делах, и знает как по нашенски от души сказать о своих делах: не очень. Так же знание тех же слов не сделает его русским и не вселит в него любовь ко всему русскому, совсем нет, но важна форма, которая поможет и нам самими собой и с другими людьми делится лучше тем самым кем мы себя представляем.
Так же и в программировании, мало сказать что ты программист, здесь оооочень много вещей которые не делают нас программистами на деле, но вот так, между делом, в расслабленном режиме, в разговоре с коллегами, стоит один раз ответить что-то касательно вопроса, ну к примеру, о SOLID, или даже может высказать свое личное особенное мнение на этот счет — нууу это солидно, немножко пусть, но SOLIDно!
Аналогия с языком не такая уже надуманная, в нашем быстро меняющем мире в разговоре айтишников чем дальше тем больше присутствует названия частных решений некоторых проблем которые быстро становятся стандартами или те же сокращения от них или иных понятий, и уже мало знать решение, термин или его значение, тебе еще стоит знать его модное сокращение и тот sidecar понятий которые он с собой тащит.