JS: Объектно-ориентированный дизайн
Теория: Конфигурация
Markdown — упрощенный язык разметки, который удобен при работе с текстом (в отличие от HTML). Браузеры не умеют отображать Markdown напрямую, поэтому он транслируется в HTML и уже затем показывается. Трансляция Markdown в HTML описывается чистой функцией. Она не зависит от внешнего окружения, детерминирована и не порождает побочных эффектов.
На входе текст (в формате Markdown), на выходе — тоже текст (в формате HTML). Если нужно изменить поведение трансляции, то достаточно передать вторым параметром объект опций.
Теперь давайте вообразим объектно-ориентированную версию этого кода. Перед тем, как двигаться дальше, попробуйте отвлечься от чтения и подумайте над следующими вопросами:
- Что мы вообще хотим получить такого от ООП, чего не дает нам чистая функция?
- Как будет выглядеть получившийся интерфейс?
Как вы помните, классы позволяют реализовать абстракцию. Можно ли сказать, что в процессе преобразования Markdown в HTML есть абстракция? Нет. Абстракция подразумевает наличие некоторого понятия (типа), значения которого обладают временем жизни. Это значит, что она создается и затем многократно и по-разному используется. Например, невозможно представить работу с пользователем в виде одной функции. Если говорить о Markdown, то конкретный текст этого формата не интересует нас сам по себе, мы не определяем над ним некоторый набор операций и не собираемся им активно пользоваться. Все, что мы хотим, прямо здесь и сейчас (в том коде) - получить HTML и забыть про Markdown.
Если бы мы хотели построить вокруг текста абстракцию, то код выглядел бы так:
В примере выше тип Markdown представляет собой абстракцию над текстом в формате Markdown. Смысла в таком коде мало, а вот проблем он доставит. Эти две строчки начнут неразрывно встречаться в каждом месте, в котором требуется получить HTML. Объект md становится сразу не нужен, как только получен HTML, у него нет времени жизни. Такой антипаттерн особенно часто встречается у новичков. Загвоздка здесь именно в том, чтобы разобраться, где у нас абстракция данных, а где нет.
Существует формальное правило, позволяющее это определить. Если создание объекта и вызов метода можно заменить на обычную функцию, то ни о какой абстракции речи не идет, и правильный подход, в данной ситуации, сводится к переносу данных из конструктора в сам метод.
В этом коде класс Markdown — тип, относящийся к транслятору, а не к тексту. У такого объекта жизненный цикл шире, чем ожидание однократного вызова функции render() (как в предыдущем случае). Он может (и должен) переиспользоваться столько раз, сколько потребуется. Для этого важно оставить функцию render() чистой и не менять состояние объекта между вызовами.
Тогда становится непонятно, зачем здесь вообще объект. И на это есть 2 причины.
- Полиморфизм подтипов. Разберем в последующих курсах.
- Вторая и главная причина (для данного случая) — Конфигурация.
Разберем последний пункт подробнее. Представьте что Markdown на проекте используется повсеместно (на Хекслете очень часто) и код генерации HTML выглядит так:
Чем больше возникает таких мест, тем больше дублируется передача опций. Изменение поведения потребует переписывания всех мест вызова этой функции. Логичным шагом было бы задать опции в одном месте и затем их переиспользовать.
Использование объекта позволяет убрать явную передачу (про которую легко забыть). Суть этого паттерна заключается в конфигурировании. То есть объект в данном случае выступает в роли контейнера, содержащего опции для Markdown, которые применяются при рендеринге, что позволяет их не передавать каждый раз.
Под конфигурированием всегда понимается передача опций (различных настроек, необходимых данной библиотеке) в конструктор во время создания объекта. Особенно полезной такая конфигурация становится тогда, когда объект создается в одном месте программы (на этапе инициализации приложения), а используется в других местах. Возможность конфигурации не навязывает саму конфигурацию. Как правило, подобные объекты можно создавать и без указания чего-либо, тогда поведение остается "дефолтным", но смысл от этого не меняется.
Другой пример — это популярная библиотека для генерации различных данных @faker-js/faker. Она позволяет создать объект, который сохранит базовую конфигурацию:
Рекомендуемые программы
Завершено
0 / 9






