Я впервые пишу сообщение на английском языке, поэтому любой отзыв, который вы можете мне дать, будет очень важен. Я буду благодарен.

Предисловие

В последние дни часть моего внимания уделяется принципам SOLID, чистой архитектуре и некоторым связанным темам, таким как шаблоны проектирования, и мне нужно признаться, что я неправильно использовал методы ООП с колледжа, я понял, что то, что я пишу был просто процедурным кодом, разделенным в разных файлах с классами и методами, не было единого преимущества от такого использования ООП, поэтому я решил изменить.

Принципы дизайна

Каждая парадигма имеет свои собственные принципы, в мире ООП эти принципы являются ТВЕРДЫМИ (их еще несколько, но они наиболее известны и используются). Итак, что это значит, эти ключевые слова SOLID? Они означают:

  • S единая ответственность;
  • O перо-закрыто;
  • Л исков Замена;
  • I сегрегация интерфейса;
  • D инверсия зависимости;

По сути, если вы создадите свое приложение, следуя всем этим принципам, ваша кодовая база станет более гибкой, абстрагированной и обслуживаемой, развитие программного обеспечения будет менее болезненным и затратным, что даст вам больше времени на внедрение новых вещей.

Принцип открытости закрыт

Принцип открытости-закрытости гласит, что наши классы должны быть открыты для расширений и закрыты для изменений. По сути, мы должны иметь возможность изменять поведение реализации во время выполнения, и для этого нам не нужно изменять кодовую базу класса, нам просто нужна помощь композиции.

Есть известный диктант, который гласит, что нам нужно предпочесть композицию наследованию, и это действительно важно. Когда мы решаем использовать наследование, возникают некоторые проблемы. Во-первых, мы нарушаем основу инкапсуляции ООП, потому что дети знают все о родителе. Второй - статическое наследование, мы не можем изменить поведение потомков даже во время выполнения, нам нужно изменить саму кодовую базу, чтобы иметь возможность изменять поведение, нарушая принцип открытого-закрытого.

Когда у нас есть композиция, у нас больше нет отношения «есть» (например, SavingsAccount является учетной записью), и мы перешли, чтобы иметь отношение «имеет» (например: AuthorizationClient имеет a HttpClient), поэтому, следуя примеру, AuthorizationClient ведет себя как обычный HttpClient, но он может изменить ваше поведение по умолчанию, например, добавив заголовок авторизации.

Пример

Представьте себе следующий сценарий, допустим, у нас есть интерфейсное клиентское приложение, написанное на React, мы используем API и нам нужно передать токен аутентификации (например, jwt). Мы решили создать интерфейс, отвечающий за отправку HTTP-запросов, поэтому на уровне данных мы создаем наш протокол HttpPostClient (только запросы POST, следуя принципу разделения интерфейса, тема для другого поста).

После этого мы создаем реализацию этого протокола на основе библиотеки axios.

Теперь у нас есть наш протокол (HttpPostClient) и наша реализация (AxiosHttpClient), почему мы не можем просто передать заголовок авторизации обычным образом в вызове метода? Нам нужно подумать, что этот заголовок должен передаваться во многих запросах и всегда будет одним и тем же: захватить токен из localStorage или из другой службы и передать его методу, который будет выполнять запрос. Если мы просто скопируем и вставим эту реализацию, мы нарушим принцип DRY (Don’t Repeat Yourself), поэтому нам нужно продумать разумный способ сделать это. Вот тут-то и пригодится паттерн-декоратор.

Шаблон декоратора - это, по сути, оболочка для объекта. Эта оболочка должна иметь тот же тип обернутого объекта, то есть реализовывать один и тот же интерфейс, и поэтому их можно обменивать таким образом, чтобы клиентский класс не заметил это изменение (подстановка Лискова).

Цель этого шаблона - добавить поведение украшенному объекту.

Возвращаясь к нашему примеру, нам нужен Decorator, который реализует интерфейс HttpPostClient и добавляет желаемое поведение к нашему AxiosHttpClient без изменения реализации класса.

Этот класс декоратора будет называться AuthorizationHttpPostClientDecorator.

Обратите внимание на несколько важных моментов:

  • Наш класс Decorator имеет тот же интерфейс, что и декорированный объект.
  • Он получает обернутый объект в конструкторе (принцип инверсии зависимостей)
  • Выполняет некоторую логику, и они вызывают метод из декорированного объекта

Это пример того, как мы можем добавить поведение к классу без изменения кода реализации.

Заключение

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

В этом примере я попытался легко продемонстрировать принцип «Открыто-Закрыто» на простом примере, чтобы вы могли понять его важность. Я выбираю шаблон декоратора, потому что ваше приложение Open-Closed является одним из самых распространенных, однако я мог бы также реализовать шаблон Proxy, он также является структурным и работает очень похожим образом.