0 added
0 removed
Original
2026-01-01
Modified
2026-02-26
1
<p>Markdown - упрощенный язык разметки, который удобен при работе с текстом (в отличие от HTML). Браузеры не умеют отображать Markdown напрямую, поэтому он транслируется в HTML и уже затем показывается. Трансляция Markdown в HTML описывается чистой функцией. Она не зависит от внешнего окружения, детерминирована и не порождает побочных эффектов.</p>
1
<p>Markdown - упрощенный язык разметки, который удобен при работе с текстом (в отличие от HTML). Браузеры не умеют отображать Markdown напрямую, поэтому он транслируется в HTML и уже затем показывается. Трансляция Markdown в HTML описывается чистой функцией. Она не зависит от внешнего окружения, детерминирована и не порождает побочных эффектов.</p>
2
<p>На входе текст (в формате Markdown), на выходе - тоже текст (в формате HTML). Если нужно изменить поведение трансляции, то достаточно передать вторым параметром объект опций.</p>
2
<p>На входе текст (в формате Markdown), на выходе - тоже текст (в формате HTML). Если нужно изменить поведение трансляции, то достаточно передать вторым параметром объект опций.</p>
3
<p>Теперь давайте вообразим объектно-ориентированную версию этого кода. Перед тем, как двигаться дальше, попробуйте отвлечься от чтения и подумайте над следующими вопросами:</p>
3
<p>Теперь давайте вообразим объектно-ориентированную версию этого кода. Перед тем, как двигаться дальше, попробуйте отвлечься от чтения и подумайте над следующими вопросами:</p>
4
<ul><li>Что мы вообще хотим получить такого от ООП, чего не дает нам чистая функция?</li>
4
<ul><li>Что мы вообще хотим получить такого от ООП, чего не дает нам чистая функция?</li>
5
<li>Как будет выглядеть получившийся интерфейс?</li>
5
<li>Как будет выглядеть получившийся интерфейс?</li>
6
</ul><p>Как вы помните, классы позволяют реализовать абстракцию. Можно ли сказать, что в процессе преобразования Markdown в HTML есть абстракция? Нет. Абстракция подразумевает наличие некоторого понятия (типа), значения которого обладают<em>временем жизни</em>. Это значит, что она создается и затем многократно и по-разному используется. Например, невозможно представить работу с пользователем в виде одной функции. Если говорить о Markdown, то конкретный текст этого формата не интересует нас сам по себе, мы не определяем над ним некоторый набор операций и не собираемся им активно пользоваться. Все, что мы хотим, прямо здесь и сейчас (в том коде) - получить HTML и забыть про Markdown.</p>
6
</ul><p>Как вы помните, классы позволяют реализовать абстракцию. Можно ли сказать, что в процессе преобразования Markdown в HTML есть абстракция? Нет. Абстракция подразумевает наличие некоторого понятия (типа), значения которого обладают<em>временем жизни</em>. Это значит, что она создается и затем многократно и по-разному используется. Например, невозможно представить работу с пользователем в виде одной функции. Если говорить о Markdown, то конкретный текст этого формата не интересует нас сам по себе, мы не определяем над ним некоторый набор операций и не собираемся им активно пользоваться. Все, что мы хотим, прямо здесь и сейчас (в том коде) - получить HTML и забыть про Markdown.</p>
7
<p>Если бы мы хотели построить вокруг текста абстракцию, то код выглядел бы так:</p>
7
<p>Если бы мы хотели построить вокруг текста абстракцию, то код выглядел бы так:</p>
8
<p>В примере выше тип Markdown представляет собой абстракцию над текстом в формате Markdown. Смысла в таком коде мало, а вот проблем он доставит. Эти две строчки начнут неразрывно встречаться в каждом месте, в котором требуется получить HTML. Объект md становится сразу не нужен, как только получен HTML, у него нет времени жизни. Такой антипаттерн особенно часто встречается у новичков. Загвоздка здесь именно в том, чтобы разобраться, где у нас абстракция данных, а где нет.</p>
8
<p>В примере выше тип Markdown представляет собой абстракцию над текстом в формате Markdown. Смысла в таком коде мало, а вот проблем он доставит. Эти две строчки начнут неразрывно встречаться в каждом месте, в котором требуется получить HTML. Объект md становится сразу не нужен, как только получен HTML, у него нет времени жизни. Такой антипаттерн особенно часто встречается у новичков. Загвоздка здесь именно в том, чтобы разобраться, где у нас абстракция данных, а где нет.</p>
9
<p>Существует формальное правило, позволяющее это определить. Если создание объекта и вызов метода можно заменить на обычную функцию, то ни о какой абстракции речи не идет, и правильный подход, в данной ситуации, сводится к переносу данных из конструктора в сам метод.</p>
9
<p>Существует формальное правило, позволяющее это определить. Если создание объекта и вызов метода можно заменить на обычную функцию, то ни о какой абстракции речи не идет, и правильный подход, в данной ситуации, сводится к переносу данных из конструктора в сам метод.</p>
10
<p>В этом коде класс Markdown - тип, относящийся к транслятору, а не к тексту. У такого объекта жизненный цикл шире, чем ожидание однократного вызова функции render() (как в предыдущем случае). Он может (и должен) переиспользоваться столько раз, сколько потребуется. Для этого важно оставить функцию render() чистой и не менять состояние объекта между вызовами.</p>
10
<p>В этом коде класс Markdown - тип, относящийся к транслятору, а не к тексту. У такого объекта жизненный цикл шире, чем ожидание однократного вызова функции render() (как в предыдущем случае). Он может (и должен) переиспользоваться столько раз, сколько потребуется. Для этого важно оставить функцию render() чистой и не менять состояние объекта между вызовами.</p>
11
<p>Тогда становится непонятно, зачем здесь вообще объект. И на это есть 2 причины.</p>
11
<p>Тогда становится непонятно, зачем здесь вообще объект. И на это есть 2 причины.</p>
12
<ol><li>Полиморфизм подтипов. Разберем в последующих курсах.</li>
12
<ol><li>Полиморфизм подтипов. Разберем в последующих курсах.</li>
13
<li>Вторая и главная причина (для данного случая) - Конфигурация.</li>
13
<li>Вторая и главная причина (для данного случая) - Конфигурация.</li>
14
</ol><p>Разберем последний пункт подробнее. Представьте что Markdown на проекте используется повсеместно (на Хекслете очень часто) и код генерации HTML выглядит так:</p>
14
</ol><p>Разберем последний пункт подробнее. Представьте что Markdown на проекте используется повсеместно (на Хекслете очень часто) и код генерации HTML выглядит так:</p>
15
<p>Чем больше возникает таких мест, тем больше дублируется передача опций. Изменение поведения потребует переписывания всех мест вызова этой функции. Логичным шагом было бы задать опции в одном месте и затем их переиспользовать.</p>
15
<p>Чем больше возникает таких мест, тем больше дублируется передача опций. Изменение поведения потребует переписывания всех мест вызова этой функции. Логичным шагом было бы задать опции в одном месте и затем их переиспользовать.</p>
16
<p>Использование объекта позволяет убрать явную передачу (про которую легко забыть). Суть этого паттерна заключается в конфигурировании. То есть объект в данном случае выступает в роли контейнера, содержащего опции для Markdown, которые применяются при рендеринге, что позволяет их не передавать каждый раз.</p>
16
<p>Использование объекта позволяет убрать явную передачу (про которую легко забыть). Суть этого паттерна заключается в конфигурировании. То есть объект в данном случае выступает в роли контейнера, содержащего опции для Markdown, которые применяются при рендеринге, что позволяет их не передавать каждый раз.</p>
17
<p>Под конфигурированием всегда понимается передача опций (различных настроек, необходимых данной библиотеке) в конструктор во время создания объекта. Особенно полезной такая конфигурация становится тогда, когда объект создается в одном месте программы (на этапе инициализации приложения), а используется в других местах. Возможность конфигурации не навязывает саму конфигурацию. Как правило, подобные объекты можно создавать и без указания чего-либо, тогда поведение остается "дефолтным", но смысл от этого не меняется.</p>
17
<p>Под конфигурированием всегда понимается передача опций (различных настроек, необходимых данной библиотеке) в конструктор во время создания объекта. Особенно полезной такая конфигурация становится тогда, когда объект создается в одном месте программы (на этапе инициализации приложения), а используется в других местах. Возможность конфигурации не навязывает саму конфигурацию. Как правило, подобные объекты можно создавать и без указания чего-либо, тогда поведение остается "дефолтным", но смысл от этого не меняется.</p>
18
<p>Другой пример - это популярная библиотека для генерации различных данных<a>@faker-js/faker</a>. Она позволяет создать объект, который сохранит базовую конфигурацию:</p>
18
<p>Другой пример - это популярная библиотека для генерации различных данных<a>@faker-js/faker</a>. Она позволяет создать объект, который сохранит базовую конфигурацию:</p>
19
19