...

суббота, 9 июня 2018 г.

Очень простое объяснение принципов SOLID

Disclaimer: Всем можно, ну а я чем хуже!?

SOLID — это набор принципов по организации кода. Фактически они декларируют некие правила, которые помогут вам сохранить свои и чужие нервы и время. А могут и не помочь.

Попробуем разобраться в этих принципах на пальцах, без примеров кода и СМС.

S — Принцип единственной ответственности (Single Responsibility Principle или SRP)


Должна быть одна и только одна причина для изменения класса («A class should have only one reason to change.» Robert C. Martin.)

Представим, что у вас на компе лежит пяток любимых песен, пара фильмов и фотки котиков. Вы валите все это в «Мои документы» и, в целом, радуетесь жизни.
Потом вы качаете еще фильмов, новый альбом любимой группы и десяток новых котиков. В «Моих документах» становится как-то не комфортно и вы раскладываете все по папочкам.
Музыка
Фильмы
Котики

Потом вы подключаете скоростной безлимит, срываетесь с катушек и качаете все серии Симпсонов, полные дискографии любимых групп, а к фоткам котиков добавляются фотки из поездки на рыбалку с друзьями. Папочки начинают ветвиться.
Музыка
  The Doors
    Waiting for the Sun
      Hello, I Love You.mp3
      ...
    ...
  RHCP
  Агутин
Видео
  Сериалы
  Фильмы
  Студия Private
Фото
  Котики
  Рыбалка
  Преферанс на даче
  куртизанки

И что мы тут имеем?
  • Музыка — отвечает ТОЛЬКО за музыку.
  • The Doors — отвечает ТОЛЬКО за музыку, сыгранную группой The Doors
  • Waiting for the Sun — отвечает ТОЛЬКО за альбом Waiting for the Sun
  • Hello, I Love You.mp3 — отвечает ТОЛЬКО за песню Hello, I Love You

Какая может быть причина изменения «The Doors»? Только одна — (качественное или количественное) изменение песен группы The Doors. А вот удаление надоевшего сериала из "/Видео/Сериалы/" такой причиной никак не может являться, так-же как и переименование «Музыка» в «Music».

Какие можно сделать выводы?

  1. SRP — это про декомпозицию (раскладываем по подпапочкам) и связность («Hello, I Love You.mp3» связана только с «Waiting for the Sun» и ей плевать на изменения в "../Сериалы". С другой стороны, все песни «The Doors» находятся внутри нее и их не должно быть в папке «Котики»).
  2. Уровень абстракции причины для изменения должен быть не выше уровня абстракции изменяемой сущности. Добавление в «Музыка» подпапки «Алла Пугачева» никак не может быть причиной изменения «Waiting for the Sun».
  3. Не нужно доводить до абсурда. Если у вас три песни, один видос и пять фоток котиков, то они прекрасно будут смотреться в одной куче — рассовывание их по папкам только все запутает. Как и сборник «The best of The Doors» не стоит разбивать на подпапки по годам, в каждой из которых будет по одной песне.

O — Принцип открытости/закрытости (Open-closed Principle или OCP)


Программные сущности (классы, модули, функции и т.п.) должны быть открыты для расширения, но закрыты для изменения («Software entities (classes, modules, functions, etc.) should be open for extension, but closed for modification.» Bertrand Meyer)

Вернемся к тому шагу нашей истории, когда вы подключили скоростной безлимит. Допустим, что в первую очередь вы накачали всевозможных фильмом про сантехников кинокомпании Private и, так как они все были про сантехников, создали папку "/Видео/Про сантехников/".
Через некоторое время вы скачали еще фильмов этой студии, но уже про доставку пиццы. Мало того, ваша новая девушка написала вам СМС «Я скачала фильм „Афоня“ и сохранила его в папку /Видео/Про сантехников/, ок?». И вроде бы все верно — про сантехника, но есть нюанс.
И тут вам становится понятно, что изменение функциональности невозможно без модификации уже существующей структуры папок(классов), а это явное нарушение принципа OCP.

Как в этом случае надо было сделать? Очень просто — изначально спроектировать систему таким образом, чтобы новый функционал не требовал изменения старого кода. Т.е. не хардкодить папку "../Про сантехников/", надеясь, что в будущем там только про них и будет, а повысить уровень абстракции до "../Студия Private/" и спокойно скармливать ей и сантехников и разносчиков пиццы и прочая-прочая…
А для Афони создать новый класс, например "../Мосфильм/", расширив класс "/Видео/"

Выводы:

  1. Думайте наперед о том, что будете делать, если появятся «другие» фильмы про сантехников. Может стоит сразу по уму сделать, чтоб не переделывать потом?
  2. Этот принцип, в основном, про абстрактные классы ("../Студия Private/").

L — Принцип подстановки Барбары Лисков (Liskov Substitution Principle или LSP)


Объекты в программе должны быть заменяемыми на экземпляры их подтипов без изменения правильности выполнения программы.

Ну тут совсем просто.
Для объяснения давайте обратимся к милоте и няшности, а конкретно к папке "/Фото/Котики/".
Котиков мы любим и фотографий собрано у нас очень много.
Фото
  Котики
    Рыжие
    Полосатые
    Мокрые
    Черные
    Манулы

Бывает даже прямо запускаем слайдшоу по всей корневой папке и любуемся. И вот, в один прекрасный момент, когда вы уже практически достигли нирваны, на экран выводится:
Невозможно отобразить файл "/Фото/Котики/Книги/Кот в сапогах.fb2"

Как потом выяснилось, ваша подруга решила поднять градус милоты и отнаследовала «Котики» новой подпапкой «Книги», грубо нарушив LSP, так как подкласс «Книги» ну никак нельзя использовать вместо базового класса «Фото».

Выводы:

  1. Название пугающее, определение сложное, но сам принцип прост и интуитивно понятен.
  2. Если ваш метод ожидает на вход «Фото», то ему должно быть все равно, какого наследника от «Фото» вы ему подсунете: «Манулы», «Рыжие» или «Мокрые», но если ему на вход придет «Книги», то он, вполне ожидаемо, поперхнется чаем.

I — Принцип разделения интерфейса (Interface Segregation Principle или ISP)


Клиенты не должны зависеть от методов, которые они не используют.

Вот тут с папочками и файликами объяснить будет сложно, но я попробую — не судите строго за некоторую натянутость.

Вам надоел стандартный проигрыватель музыки и вы решили скачать новый, супер модный и хайповый. Он даже умеет отображать обложку музыкального альбома и выводить субтитры исполняемой песни. Но вот беда, если в папке альбома отсутствуют файлы «cover.jpg» и «subtitles.txt», то проигрыватель падает с ошибкой. И вот вы, проклиная все на свете, начинаете создавать во всех подпапках с альбомами эти файлы заглушки.

Т.е., проводя не корректные аналогии, мы обязали класс «Музыка» и всех его наследников реализовывать интерфейс «AudioCoverSubtitles». При этом, полностью этот интерфейс реализует только альбом «Waiting for the Sun», альбом «The best of The Doors» реализует только часть «Audio+Cover», а все остальные только «Audio».

Это подводит нас к мысли, что имеет смысл разделить толстый интерфейс «AudioCoverSubtitles» на три небольших «Audio», «Cover» и «Subtitles» и применять их только там, где они действительно нужны.

Выводы:

  1. ISP — это, внезапно, про разделение интерфейсов.
  2. Если ваш интерфейс вынуждает вас создавать методы заглушки, то это плохой интерфейс и по нему стоит пройтись ножницами.

D — Принцип инверсии зависимостей (dependency inversion principle или DIP)


Модули верхних уровней не должны зависеть от модулей нижних уровней. Оба типа модулей должны зависеть от абстракций.
Абстракции не должны зависеть от деталей. Детали должны зависеть от абстракций.

Модуль «The Doors» не должен зависеть от того, какого рода аудио файлы в нем сложены, .mp3, .flac или .wav.
Модуль «The Doors», его подмодуль «Waiting for the Sun» (и все остальные), зависят от верхнеуровневой абстракции «Музыка», которая определяет их реализацию (то, что внутри у них музыка).

Допустим мы решили разделить хранение музыки по принципу сжатия — «с потерями» и «без потерь». Это детали, которые объединяет зависимость от абстракции «Музыка» — в них, в конечном итоге, должна таки быть музыка. При этом сама абстракция «Музыка» не зависит от этих деталей. Ей все равно, с потерями там музыка или без них — она как была музыкой, так ей и остается.

Выводы:

  1. DIP — это про то, частное должно зависеть от общего, а не наоборот.
  2. DIP — это «Больше абстракций богу абстракций!»
  3. DIP — это еще и про причины и следствия, про правильный ответ на вопрос «Ветви качаются от того, что дует ветер или ветер дует от того, что ветви качаются»

Спасибо за внимание и хороших выходных!

Let's block ads! (Why?)

Комментариев нет:

Отправить комментарий