# Паттерны проектирования — это общий словарь

Экспресс-курс по классическим паттернам проектирования. 20 паттернов из каталога «банды четырёх» — Factory, Builder, Adapter, Decorator, Strategy, Observer, State и другие — у каждого английское название, схема, карточка «проблема → идея → пример → цена» и связи с соседями. В конце — шпаргалка по всем паттернам на одной странице.

- **Author:** Фёдор Чищин
- **Level:** intro
- **Reading time:** ~30 минут чтения
- **Published:** 2026-06-02
- **Source:** https://fedorthinks.com/ru/learn/design-patterns-express

---

## 1. Что такое паттерн

Паттерн проектирования — это названное, переиспользуемое решение проблемы, которая всплывает в коде снова и снова. Это словарь, а не библиотека — его не устанавливают, его узнают.

### Design Pattern — имя для приёма, который ты и так делаешь

> Футболисты не изобретают «стенку» по ходу матча. У приёма есть имя, и назвать его быстрее, чем описывать весь манёвр.

**Паттерн проектирования (design pattern)** — это приём, который толковые разработчики и так изобретают руками. Имя превращает абзац объяснений в одно слово, общее для всей команды. Когда кто-то говорит «оберни это в Decorator», все сразу видят форму — и **в этом весь смысл паттерна: общий словарь** для приёмов, которые ты сделал бы в любом случае.

#### Design Pattern (паттерн проектирования)

- **Что это:** Названное решение проблемы, которая повторяется в коде снова и снова.
- **Чем не является:** Не библиотека: его не устанавливают, а узнают и пишут сами.
- **Масштаб:** Живёт внутри кода одного модуля — в отличие от архитектурных паттернов, которые решают планировку всей системы.
- **Зачем:** Общий язык: одно слово вместо абзаца объяснений.

### Gang of Four — паттерны находят, а не изобретают

> Никто не изобретал арку. Строители раз за разом обнаруживали, что это самый прочный способ перекрыть пролёт, — и ей дали имя.

**«Банда четырёх» (Gang of Four, GoF)** — четыре автора книги «Design Patterns». Они не придумали 23 хитрых трюка; они **каталогизировали** решения, которые снова и снова всплывали в хорошем коде. Поэтому паттерн — не цель, в которую надо попасть, а форма, к которой ты приходишь сам, когда задача того требует. **Если ты втискиваешь паттерн силой — скорее всего, у тебя ещё нет его проблемы.**

### Карта: три семьи, три вопроса

> На кухне есть инструменты для трёх задач: приготовить еду, выложить на тарелку и подать. Паттерны делятся так же.

**Порождающие (creational)** паттерны — про то, как объекты рождаются: кто их строит и как. **Структурные (structural)** — про то, как объекты складываются в большие формы. **Поведенческие (behavioural)** — про то, как объекты общаются и делят ответственность. Почти любой классический паттерн — это один из этих трёх ответов.

_Diagram: Три семьи и 20 паттернов курса — по ним идут главы 2–5._

### Indirection — паттерн, который не нужен, это просто сложность

> Швейцарский нож в кармане — удобно. Привинтить все двадцать инструментов к входной двери — нет.

Любой паттерн добавляет **прослойку (indirection)** — слой между тобой и вещью. Это оправдано, когда прослойка покупает гибкость, которой ты реально воспользуешься, и чистая трата — когда нет. Главная ошибка не в незнании паттернов, а в том, чтобы **тянуться за паттерном раньше, чем появилась проблема.**

### Как читать каждый паттерн

> Паспорт: одинаковые поля у всех, поэтому их легко сравнивать.

У каждого паттерна дальше одно и то же: **английское название** (это термин — запомни его), образ из жизни, **схема** и **карточка** с полями: _проблема_ (что болит), _идея_ (как решает), _пример_, _цена_ (что ты платишь), _когда брать_ и _связи_ с другими паттернами. В конце курса — шпаргалка со всеми именами на одной странице.

> **Прежде чем называть паттерн:** «Есть ли у меня та повторяющаяся проблема, которую он решает, — или мне просто нравится слово?»

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

## 2. Порождающие паттерны

Creational patterns — как объекты появляются на свет: без россыпи `new` повсюду и без приваривания кода к конкретным классам.

### Factory — проси вещь по имени, а не по рецепту

> Кофемашина: ты жмёшь «латте» и получаешь его. Ты не мелешь, не взбиваешь и не наливаешь сам — и не обязан знать, как это устроено.

**Фабрика (Factory)** выдаёт тебе объект, минуя прямой вызов конструктора, так что вызывающий код никогда не зависит от конкретного класса. Он знает только **интерфейс**. **Это покупает свободу менять то, что строится, не трогая того, кто попросил.**

_Diagram: Клиент просит по имени; фабрика выбирает класс; клиент видит только интерфейс PaymentProvider._

#### Factory (Factory Method, фабрика)

- **Проблема:** `new StripeProvider()` разбросан по коду — код приварен к классу.
- **Идея:** Просить объект у фабрики; она решает, какой класс построить.
- **Пример:** `createPaymentProvider("stripe")` возвращает `PaymentProvider`. Перейти на PayPal — поменять фабрику, а не каждое место вызова.
- **Цена:** Лишняя прослойка. Фабрика, которая строит ровно одну вещь, — запах.
- **Когда брать:** Реализаций несколько, или они будут меняться.
- **Связи:** **Abstract Factory** — та же идея для целого семейства объектов.

### Abstract Factory — целое семейство в едином стиле

> Покупаешь мебельный гарнитур — «викторианский» или «модерн» — где каждый предмет приходит в одном стиле, без разношёрстных стульев.

Когда объекты должны идти согласованными **семьями (families)**, **абстрактная фабрика (Abstract Factory)** строит весь набор сразу, так что части подходят друг к другу. Мощно — но это тяжёлая машинерия, оправданная, только когда семьи реальны.

_Diagram: Одна фабрика — один согласованный набор: кнопка, меню и диалог в одном стиле._

#### Abstract Factory (абстрактная фабрика)

- **Проблема:** Объекты должны сочетаться между собой, а их легко перемешать.
- **Идея:** Одна фабрика выдаёт весь набор в одном стиле.
- **Пример:** UI-тулкит: согласованные кнопки, меню и диалоги под macOS или под Windows из одной фабрики.
- **Цена:** Тяжёлая машинерия: много интерфейсов и классов.
- **Когда брать:** Только когда семейства настоящие, и их больше одного.
- **Связи:** Строится из **Factory**. «Абстрактная фабрика на один продукт» — классика переусложнения.

### Builder — собирай сложный объект шаг за шагом

> Заказываешь бургер под себя — булка, котлета, без лука, двойной сыр — по одному выбору за раз, потом «готово».

Когда у объекта много необязательных частей, **строитель (Builder)** позволяет задавать их по кусочку, а не через монструозный конструктор на двенадцать аргументов. В конце вызываешь `build()` и получаешь готовый объект. **Он меняет один сбивающий с толку конструктор на читаемую цепочку.**

_Diagram: Цепочка шагов → build() → готовый объект. Вместо конструктора, где не понять, какой аргумент какой._

#### Builder (строитель)

- **Проблема:** Конструктор на двенадцать аргументов, половина из них необязательна.
- **Идея:** Задавать части по одной, в конце — `build()`.
- **Пример:** `QueryBuilder().select("name").where("age > 18").limit(10).build()`.
- **Цена:** Ещё один класс рядом с основным.
- **Когда брать:** У объекта много необязательных частей.
- **Связи:** **Factory** решает, _что_ построить; **Builder** — _как_ собрать сложное.

### Singleton — ровно один, общий для всех

> У страны один президент. Все, кто говорит «президент», имеют в виду одного и того же человека — их не двое.

**Одиночка (Singleton)** гарантирует единственный экземпляр с одной глобальной точкой доступа. Но обращайся осторожно: singleton — это **глобальное состояние в красивом пальто**, а глобальное состояние мешает тестировать и рассуждать.

_Diagram: Все модули дотягиваются до одного и того же экземпляра — удобно, но это глобальное состояние._

#### Singleton (одиночка)

- **Проблема:** Нужен ровно один общий экземпляр.
- **Идея:** Класс сам гарантирует один экземпляр и одну точку доступа.
- **Пример:** Конфигурация или логгер, из которых читают все.
- **Цена:** Глобальное состояние: тесты и рассуждения становятся сложнее.
- **Когда брать:** Редко. Часто лучше один экземпляр, который ты **передаёшь явно**, а не достаёшь через глобал.
- **Связи:** Порождающий, как **Factory**, но про «сколько», а не про «какой».

### Prototype — копируй заполненное, а не строй с нуля

> Сделать копию заполненного бланка быстрее, чем заполнять пустой с нуля.

Когда создавать объект с нуля дорого или муторно, **прототип (Prototype)** предлагает **клонировать (clone)** существующий и подправить. Удобно, когда объекты дороги в постройке и в основном похожи.

_Diagram: Настроенный объект клонируют и слегка правят — вместо того чтобы собирать заново._

#### Prototype (прототип)

- **Проблема:** Собирать объект с нуля долго и муторно.
- **Идея:** Взять готовый объект, скопировать, подправить отличия.
- **Пример:** Дублировать настроенного игрового противника или стилизованный узел документа.
- **Цена:** Копировать надо аккуратно: что копируется, а что остаётся общим.
- **Когда брать:** Объекты дороги в постройке и в основном похожи.
- **Связи:** Альтернатива **Factory**: не «построй», а «скопируй».

> **Порождающий вопрос:** «Кто решает, какой конкретный класс будет построен, — и насколько тяжело это решение поменять?»

> Спрячь `new`. Чем меньше мест знает, как строится объект, тем свободнее ты его меняешь.

## 3. Структурные паттерны

Structural patterns — как объекты складываются в большие структуры: стыкуя несовместимые части и добавляя возможности без переписывания.

### Adapter — переходник между двумя интерфейсами

> Зарядка ноутбука за границей — устройство в порядке, розетка в порядке; нужен только маленький переходник между ними.

**Адаптер (Adapter)** оборачивает один интерфейс так, чтобы он выглядел как другой. Две вещи, не созданные для совместной работы, начинают сотрудничать. **Так ты не даёшь чужому API протечь во весь твой код.**

_Diagram: Твой код зовёт pay(); адаптер переводит это в charge() вендора._

#### Adapter (адаптер, wrapper)

- **Проблема:** Чужой интерфейс не совпадает с твоим и расползается по коду.
- **Идея:** Обёртка, которая переводит вызовы из одного интерфейса в другой.
- **Пример:** Сторонний платёжный SDK обёрнут так, что удовлетворяет твоему `PaymentProvider`.
- **Цена:** Ещё один слой, который надо обновлять, когда меняется API вендора.
- **Когда брать:** Подключаешь сторонний или старый код.
- **Связи:** Оборачивает объект, как **Decorator** и **Proxy**, но **меняет интерфейс**.

### Decorator — добавляй начинку, не меняя пиццу

> Простая пицца, потом сыр, потом грибы — каждый слой оборачивает предыдущий и что-то добавляет, и это всё ещё пицца.

**Декоратор (Decorator)** оборачивает объект и добавляет поведение — без правки оригинала и без наследования. Интерфейс остаётся тем же, поэтому слои можно ставить друг на друга. **Так ты добавляешь возможности в сочетаниях, которые никто не обязан был предусмотреть.**

_Diagram: Поток обёрнут в сжатие, а сжатие — в шифрование. Снаружи это всё ещё поток._

#### Decorator (декоратор, обёртка)

- **Проблема:** Нужны добавки в любых сочетаниях; подклассов на каждое не напасёшься.
- **Идея:** Обернуть объект, добавить одно поведение, сохранить интерфейс.
- **Пример:** Поток данных → сжатие → шифрование; каждый слой можно поставить или снять.
- **Цена:** Много мелких обёрток; стек слоёв труднее отлаживать.
- **Когда брать:** Возможности надо комбинировать в рантайме.
- **Связи:** По форме как **Proxy**, но цель — добавить, а не контролировать. Чистый пример **composition over inheritance**.

### Facade — одна простая стойка перед бардаком за кулисами

> Консьерж в отеле — ты говоришь «нужно такси и столик на ужин», а он разруливает клубок звонков за стойкой.

**Фасад (Facade)** даёт простую, единую точку входа в сложную **подсистему (subsystem)** и прячет её движущиеся части. **Он сжимает большую поверхность до одной двери, которая нужна большинству вызывающих.**

_Diagram: Один вызов convert() — а за ним кодеки, буферы и аудиопотоки._

#### Facade (фасад)

- **Проблема:** Чтобы сделать простую вещь, надо знать десяток классов подсистемы.
- **Идея:** Одна простая дверь, которая дирижирует подсистемой.
- **Пример:** `VideoConverter.convert(file, "mp4")` втихую управляет кодеками, буферами и аудиопотоками.
- **Цена:** Сложность не исчезает — она спрятана. Тонкий контроль всё равно идёт мимо фасада.
- **Когда брать:** Большинству вызывающих нужен один-два простых сценария.
- **Связи:** **Adapter** меняет интерфейс одной вещи; **Facade** упрощает целую подсистему.

### Proxy — подставное лицо, контролирующее доступ

> Ассистент знаменитости — ты не дотягиваешься до звезды напрямую; ассистент фильтрует, планирует, а иногда отвечает за неё.

**Заместитель (Proxy)** встаёт перед объектом и контролирует доступ к нему: для **ленивой загрузки (lazy loading)**, прав, кэширования или общения с чем-то удалённым. Тот же интерфейс — лишние ворота перед ним.

_Diagram: Клиент говорит с прокси как с настоящим объектом; прокси решает, когда и пускать ли дальше._

#### Proxy (заместитель)

- **Проблема:** Объект дорого грузить, к нему нужны права, или он вообще на другой машине.
- **Идея:** Заместитель с тем же интерфейсом стоит перед настоящим объектом.
- **Пример:** Прокси картинки не грузит файл, пока его не показывают; прокси доступа проверяет права, прежде чем пробросить вызов.
- **Цена:** Лишний шаг в каждом вызове; задержка спрятана от вызывающего.
- **Когда брать:** Ленивая загрузка, права, кэш, удалённый объект.
- **Связи:** Форма как у **Decorator**, цель другая — контроль доступа.

### Composite — дерево и лист на один манер

> Папка хранит файлы и другие папки. «Посчитать размер» работает одинаково, спрашиваешь ли ты один файл или всё дерево.

**Компоновщик (Composite)** позволяет обращаться с одиночным объектом (**лист, leaf**) и группой объектов (**ветка, composite**) одинаково — у них один интерфейс. **Так рекурсивные структуры превращаются в то, с чем работаешь без особых случаев на каждом уровне.**

_Diagram: Папка и файл отвечают на одни и те же вызовы — дерево обходится без особых случаев._

#### Composite (компоновщик, дерево)

- **Проблема:** Работа с деревом требует особого случая на каждом уровне.
- **Идея:** Лист и ветка делят один интерфейс; ветка просто зовёт детей.
- **Пример:** Интерфейс, где и кнопка, и панель-полная-кнопок отвечают на `render()` и `getSize()`.
- **Цена:** Общий интерфейс бывает слишком общим: не все операции имеют смысл у листа.
- **Когда брать:** Данные по природе — дерево: папки, UI, документы.
- **Связи:** Обходят его через **Iterator**; новые операции добавляют через **Visitor**.

> **Структурный вопрос:** «Я меняю то, что объект делает, — или только то, как он обёрнут и как до него дотягиваются?»

> Композиция вместо наследования: защёлкивай поведение в рантайме, а не замораживай его в дереве классов.

## 4. Общение и разделение работы

Первая половина behavioural patterns: как объекты делят работу и говорят друг с другом — чтобы ответственность была разрезана чисто и нужный код запускался в нужный момент.

### Strategy — подмени алгоритм, оставь вызывающего

> Приложение карт: та же поездка, но ты выбираешь «быстрее», «короче» или «без платных дорог», и маршрут строится иначе. Ты выбираешь стратегию; приложение просто следует ей.

**Стратегия (Strategy)** делает алгоритм взаимозаменяемым в рантайме: вызывающий остаётся прежним, а способ меняется. В современных языках это часто **просто передача функции**, а не целого класса — и в этом суть: паттерн — это идея, а не церемония.

_Diagram: Оформление заказа зовёт PricingStrategy; какая именно цена — решается в рантайме._

#### Strategy (стратегия)

- **Проблема:** Растущая лестница `if` по вариантам одного алгоритма.
- **Идея:** Алгоритм — подменяемый объект (или функция) за одним интерфейсом.
- **Пример:** Оформление заказа принимает `PricingStrategy`: обычная, для участника или праздничная распродажа.
- **Цена:** Strategy на один алгоритм, который никогда не меняется, — лишняя.
- **Когда брать:** Вариантов два и больше, и выбор делается в рантайме.
- **Связи:** По форме — как **State**. В современном коде часто просто функция.

### Observer — подпишись, и узнаешь, когда изменится

> Рассылка — ты подписываешься один раз, и каждый новый выпуск приходит к тебе. Издатель не звонит каждому читателю; он просто шлёт по списку.

**Наблюдатель (Observer)**: объекты-**подписчики (subscribers)** подписываются на **субъект (subject)** и получают уведомление, когда тот меняется. Субъект при этом не знает, кто они. **Это становой хребет событийного и реактивного кода.**

_Diagram: Ячейка изменилась → notify() → все зависящие графики и таблицы обновились сами._

#### Observer (наблюдатель, pub/sub)

- **Проблема:** Объект должен оповещать многих, не зная их поимённо.
- **Идея:** Список подписчиков + `notify()` при каждом изменении.
- **Пример:** Ячейка таблицы обновляет все зависящие графики; UI-фреймворки реагируют на состояние; pub/sub повсюду.
- **Цена:** Цепочки уведомлений трудно отследить; забытая подписка живёт вечно.
- **Когда брать:** На одно изменение реагируют несколько независимых частей.
- **Связи:** Основа событийного кода — того же **Event-driven**, только внутри одной программы.

### Command — оберни запрос в объект

> Заказной чек в ресторане — запрос «стол 5, два кофе» становится бумажкой, которую можно поставить в очередь, переставить, залогировать и даже порвать.

**Команда (Command)** превращает действие в самостоятельный объект. Теперь его можно поставить в очередь, залогировать, отложить или **отменить (undo)**. **Так действие становится тем, что можно сохранить и проиграть заново.**

_Diagram: Каждая правка — объект с do() и undo(); история команд даёт undo/redo и макросы._

#### Command (команда)

- **Проблема:** Действие нужно отложить, повторить, залогировать или отменить.
- **Идея:** Упаковать действие в объект со всем, что нужно для выполнения.
- **Пример:** Каждая правка в редакторе — команда: отсюда undo/redo и макросы. Очередь задач — команды, ждущие своей очереди.
- **Цена:** Объект на каждое действие; отмену надо продумать для каждой команды.
- **Когда брать:** Undo/redo, очереди, макросы, журнал действий.
- **Связи:** Для undo часто идёт в паре с **Memento**.

### Chain of Responsibility — передавай дальше, пока кто-то не разберётся

> Уровни поддержки — первая линия пробует, эскалирует специалисту, затем менеджеру, пока кто-то реально не решит вопрос.

**Цепочка обязанностей (Chain of Responsibility)**: запрос идёт по цепочке **обработчиков (handlers)**; каждый либо разбирается с ним, либо передаёт дальше. **Так отправитель отвязан от того, кто в итоге сделает работу.**

_Diagram: Веб-middleware: auth → логирование → rate limit → маршрут. Любое звено может остановить запрос._

#### Chain of Responsibility (цепочка обязанностей, middleware)

- **Проблема:** Отправитель не должен знать, кто именно обработает запрос.
- **Идея:** Цепочка обработчиков: каждый делает свою часть или передаёт дальше.
- **Пример:** Веб-middleware: аутентификация, потом логирование, потом rate-limit, потом сам маршрут.
- **Цена:** Порядок звеньев важен; запрос может пройти всю цепь и никем не обработаться.
- **Когда брать:** Несколько независимых проверок или шагов перед основной работой.
- **Связи:** В вебе ты почти всегда встречаешь его под именем **middleware**.

> **Вопрос про взаимодействие:** «Могу ли я поменять, кто это обрабатывает или как, — так, чтобы вызывающий не заметил?»

> Хорошие поведенческие паттерны дают двум кускам сотрудничать, не вшивая один в другой намертво.

## 5. Состояние, шаги, обход

Вторая половина behavioural patterns: как поведение объекта меняется с его состоянием, как ты идёшь по коллекциям и как фиксируешь скелет, оставляя один шаг открытым.

### State — поведение, которое меняется с режимом

> Светофор — зелёный, жёлтый, красный — где каждый цвет решает, что происходит сейчас и какой цвет будет следующим. Светофор тот же, поведение разное в каждом состоянии.

**Состояние (State)** позволяет объекту менять поведение по мере смены внутреннего состояния. Клубок `if` и `switch` заменяется ясными **состояниями (states)** и **переходами (transitions)** — это маленький **конечный автомат (state machine)**. **Так каша из флагов превращается в аккуратную машинку.**

_Diagram: Заказ: pending → paid → shipped; отменить можно только из pending и paid._

#### State (состояние, state machine)

- **Проблема:** Поведение зависит от режима, и код зарастает флагами и `switch`.
- **Идея:** Каждое состояние — отдельный объект со своими правилами и переходами.
- **Пример:** Заказ ведёт себя по-разному как `pending`, `paid`, `shipped` или `cancelled`; каждое состояние знает только свои правила и то, чем может стать.
- **Цена:** Много маленьких классов; на два состояния хватит обычного `if`.
- **Когда брать:** Состояний много, а переходы между ними важны.
- **Связи:** По форме как **Strategy**, но объект переключает состояние сам, по ходу жизни.

### Iterator — иди по коллекции, не заглядывая внутрь

> Кнопки «дальше» и «назад» на пульте — ты переключаешь каналы, не зная, как они хранятся.

**Итератор (Iterator)** даёт единый способ пройти коллекцию, не раскрывая, как она устроена — массив, дерево или связанный список. **Он настолько полезен, что язык обычно встраивает его внутрь** — `for..of`, генераторы, `__iter__`. Это самый ясный пример того, как паттерн дорастает до фичи языка.

_Diagram: Массив, дерево и список отдают один и тот же next() — цикл не знает, что внутри._

#### Iterator (итератор)

- **Проблема:** Код обхода зависит от того, как устроена коллекция.
- **Идея:** Единый способ брать «следующий элемент», что бы ни было внутри.
- **Пример:** `for (item of collection)` работает одинаково над списком и над своей структурой.
- **Цена:** Почти нулевая — обычно он уже встроен в язык.
- **Когда брать:** Всегда, но через встроенные средства, а не руками.
- **Связи:** Обходит деревья из **Composite**.

### Template Method — фиксированный рецепт с одним пропуском

> Рецепт, одинаковый каждый раз, — кроме «добавь специю на свой вкус» на четвёртом шаге. Скелет зафиксирован; один шаг — твой.

**Шаблонный метод (Template Method)** задаёт **скелет (skeleton)** операции в базовом классе и позволяет переопределять отдельные шаги, не меняя общей формы. Полезно, когда много потоков делят форму, но различаются в одном-двух местах.

_Diagram: Базовый импортёр открывает, читает, разбирает и сохраняет; подклассы дают только шаг разбора._

#### Template Method (шаблонный метод)

- **Проблема:** Несколько потоков одной формы копируют друг друга почти целиком.
- **Идея:** Скелет — в базовом классе; изменчивые шаги — в подклассах.
- **Пример:** Импортёр открывает, читает, **разбирает (это заполняешь ты)** и сохраняет; импортёры CSV и JSON подставляют только шаг разбора.
- **Цена:** Держится на наследовании; скелет трудно поменять потом.
- **Когда брать:** Форма общая, различия — в одном-двух местах.
- **Связи:** **Strategy** решает похожую задачу через композицию, а не наследование.

### Mediator, Visitor, Memento — остальное на одном дыхании

> В ящике с инструментами есть те, за которыми тянешься раз в месяц, а не каждый день, — но знать об их существовании всё равно стоит.

Ещё горстка иногда оправдывает своё место. **Mediator** — диспетчерская, чтобы объекты говорили через один хаб, а не клубок прямых связей. **Visitor** — добавить новые операции к структуре, не правя её классы. **Memento** — захватить состояние объекта, чтобы восстановить его позже. Знай имена; тянись за ними, только когда появилась именно эта проблема.

_Diagram: Mediator: всё через хаб. Visitor: новая операция обходит классы снаружи. Memento: снимок и восстановление._

#### Mediator (посредник)

- **Что это:** Один хаб, через который объекты общаются вместо прямых связей.
- **Образ:** Диспетчерская вышка: самолёты говорят с ней, а не друг с другом.
- **Когда брать:** Прямых связей между объектами стало слишком много.

#### Visitor (посетитель)

- **Что это:** Новая операция над структурой, вынесенная в отдельный объект.
- **Пример:** Экспорт всех фигур документа — без правки классов самих фигур.
- **Когда брать:** Структура стабильна, а операций над ней становится всё больше.

#### Memento (снимок)

- **Что это:** Сохранённое состояние объекта, к которому можно вернуться.
- **Пример:** Точки сохранения в игре, снимки для отмены в редакторе.
- **Связи:** Вместе с **Command** даёт undo.

> **Вопрос про управление:** «Этот лес из `if` — не скрытый ли это State-автомат или Strategy?»

> Когда паттерн становится ключевым словом языка — перестань писать паттерн и используй ключевое слово.

## 6. Современный взгляд

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

### Language features — многие паттерны теперь просто фичи языка

> Раньше дорогу объясняли по ориентирам; теперь телефон сам ведёт. Навык не исчез — он впитался в инструмент.

Iterator — это `for..of`. Strategy — часто переданная функция. Decorator и Observer встроены в современные фреймворки. Когда язык даёт тебе форму бесплатно, **писать полный паттерн руками — просто церемония (boilerplate)**. Идея по-прежнему важна; шаблонный код — обычно нет.

_Diagram: Слева паттерн из каталога, справа — что язык или фреймворк уже дают вместо него._

### Pattern-itis — реальная болезнь

> Повар, вываливающий в одно блюдо всю полку специй, получает не более богатый вкус, а несъедобное месиво.

**Паттерн-ит (pattern-itis)** — классический запах **переусложнения (over-engineering)**: тянуться за паттернами, чтобы выглядеть изощрённо. И сейчас хуже — **AI-ассистент с радостью сгенерит «многоуровневую Abstract Factory» там, где должно быть три строки**. Более простой код почти всегда — более сеньорский выбор.

#### Pattern-itis (паттерн-ит, over-engineering)

- **Что это:** Паттерны ради паттернов, а не ради снятой боли.
- **Симптомы:** Абстрактная фабрика на один продукт, Strategy на один алгоритм, который никогда не меняется, пять слоёв обёрток вокруг одного `if`.
- **Почему сейчас хуже:** AI-ассистенты генерируют такие конструкции охотно и быстро.
- **Лекарство:** Сначала самый простой код; паттерн — только когда появилась боль.

### Паттерны — это словарь, а не закон

> Знание множества слов не делает хорошего писателя. Хорошего делает знание, какое слово — и когда промолчать.

Настоящая ценность каталога — **общий язык**: «давай поставим тут Facade» мгновенно доходит до любого, кто знает термин, и на команде это стоит немало. Но цель всегда — самый простой код, решающий задачу. Паттерн — это средство; назвать его — никогда не достижение.

> **Современный тест:** «Справился бы более простой код — функция, обычный объект, фича языка — с этим так же хорошо?»

> Выучи все паттерны, чтобы их узнавать. Используй так мало, как только можешь себе позволить.

## 7. Как выбирать

Паттерны — это ответы. Мастерство — подобрать их к реальному вопросу и понять, когда правильный ответ — никакого паттерна.

### Пусть паттерн вырастает из боли

> Ты не берёшь гаечный ключ, пока не нашёл болт. Сначала видишь проблему — потом тянешься за инструментом, который к ней подходит.

Хорошее применение паттерна — это обычно **рефакторинг (refactoring)**, а не стартовый чертёж: ты пишешь простое, чувствуешь конкретную боль — эта лестница `if` всё растёт, этот класс слишком много знает о том, как он построен, — и **тогда** паттерн, который её снимает, очевиден. Втискивать паттерны заранее — это как строить соборы, которых никто не просил.

### Называй, только когда имя помогает

> Ты не говоришь «я выполнил стенку» в обычной беседе. Но на поле, с партнёрами, это слово экономит целое предложение.

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

### Паттерны связаны между собой

> Слова в языке не живут поодиночке: у них есть синонимы, пары и родственники.

Adapter, Decorator и Proxy — **одна форма**: обёртка вокруг объекта, разные цели. Strategy и State **похожи по форме**. Command и Memento вместе дают **undo**. Abstract Factory **строится из** Factory. Composite обходят **Iterator**. Observer — **основа** событийного кода.

_Diagram: Главные связи между паттернами курса._

#### Прежде чем тянуться за паттерном

- **Какую повторяющуюся проблему он решает?** Скажи одним предложением.
- **Есть ли у меня эта проблема сейчас**, или я гадаю про будущее?
- **Справилась бы обычная функция или объект?** Сначала попробуй так.
- **Не даёт ли мне язык это** уже бесплатно?
- **Сделает ли имя код яснее** для следующего человека — или просто наряднее?
- **Я рефакторю к нему** или втискиваю заранее?

#### Признаки, что ты переусложнил

- У тебя **фабрика, которая строит ровно одну вещь**.
- **Strategy с единственной стратегией**, которая никогда не меняется.
- Интерфейсов и обёрток **больше, чем реального поведения**.
- Ты добавил паттерн, **чтобы выглядеть сеньором**, а не чтобы снять боль.
- Новому читателю нужна **UML-диаграмма**, чтобы проследить три строки логики.

#### Признаки, что ты выбрал хорошо

- Паттерн **убрал растущую лестницу `if`/`switch`**.
- Ты можешь **подменить реализацию**, не трогая вызывающих.
- Коллега **узнал форму** по имени сразу.
- Обёртка **окупается** — ты реально пользуешься гибкостью.
- С паттерном код **проще, чем без него**, а не просто хитрее.

## Шпаргалка: все 20 паттернов и главные идеи

### Основы

- **Design Pattern** (паттерн проектирования): Названное решение повторяющейся проблемы в коде. Словарь, а не библиотека.
- **Gang of Four** (GoF, «банда четырёх»): Авторы книги «Design Patterns», которые собрали каталог из 23 паттернов.
- **Indirection** (прослойка): Слой между тобой и вещью. Цена любого паттерна.
- **Pattern-itis** (переусложнение): Паттерны ради вида, а не ради боли. Простой код почти всегда лучше.

### Порождающие (creational)

- **Factory** (Factory Method): Просишь объект по имени; фабрика выбирает класс.
- **Abstract Factory** (абстрактная фабрика): Фабрика целого согласованного семейства объектов.
- **Builder** (строитель): Сложный объект по шагам, в конце `build()`.
- **Singleton** (одиночка): Ровно один экземпляр на всех. Осторожно: глобальное состояние.
- **Prototype** (прототип): Клонируй готовый объект и подправь.

### Структурные (structural)

- **Adapter** (адаптер): Переходник: один интерфейс выглядит как другой.
- **Decorator** (декоратор): Обёртка добавляет поведение, интерфейс тот же.
- **Facade** (фасад): Одна простая дверь в сложную подсистему.
- **Proxy** (заместитель): Стоит перед объектом и контролирует доступ.
- **Composite** (компоновщик): Лист и дерево — один интерфейс.

### Поведенческие: общение (behavioural)

- **Strategy** (стратегия): Подменяемый алгоритм; часто просто функция.
- **Observer** (наблюдатель): Подписчики узнают об изменениях сами.
- **Command** (команда): Действие как объект: очередь, лог, undo.
- **Chain of Responsibility** (цепочка обязанностей): Обработчики по цепочке; в вебе — middleware.

### Поведенческие: состояние и шаги

- **State** (состояние): Каждое состояние — свои правила и переходы.
- **Iterator** (итератор): Обход коллекции, не заглядывая внутрь. Обычно `for..of`.
- **Template Method** (шаблонный метод): Скелет зафиксирован, один шаг — твой.
- **Mediator** (посредник): Все говорят через один хаб.
- **Visitor** (посетитель): Новая операция без правки классов.
- **Memento** (снимок): Сохранить состояние и вернуться к нему.

> Лучшее применение паттерна — то, которого читатель даже не замечает, потому что код стал казаться очевидным.

Конец экспресс-курса · 7 глав · 20 паттернов

Дальше — первоисточник: «Design Patterns» «банды четырёх» и её более добрые современные спутники — «Head First Design Patterns», refactoring.guru, «Рефакторинг» Мартина Фаулера. Но читай их так, как учат шахматные дебюты: не чтобы зазубрить ходы, а чтобы узнавать позицию, когда она появится на твоей доске.
