Содержание
На ревью два разработчика спорят об одном классе. Один говорит: «здесь нужен Декоратор». Второй: «это просто if». Через месяц в коде — три слоя обёрток, которые никто не может прочитать, и баг в порядке вызовов. Знакомо?
Приёмы объектно-ориентированного проектирования (оригинал Design Patterns, «банда четырёх», GoF, 1994) — не инструкция «вставь шаблон в каждый модуль». Это словарь для повторяющихся проблем проектирования: как назвать решение, обсудить его на ревью и не изобретать велосипед в одиночку. Ниже — разбор своими словами: что из книги живёт в 2026 году, где превращается в карго-культ, и как ИИ усугубляет «pattern soup». Выжимка не заменяет оригинал.
Тезис книги
Шаблон проектирования — это именованное, проверенное решение повторяющейся проблемы в контексте объектно-ориентированных систем. GoF даёт язык: «Strategy», «Observer», «Factory Method» — не как модные слова, а как ссылки на структуру, последствия и компромиссы.
Книга появилась, когда ООП только становился мейнстримом. Многие примеры на C++ и Smalltalk устарели синтаксически, но проблемы те же: как изолировать изменение, как связать объекты без спагетти, как создавать семейства объектов. Главная ошибка читателя — учить 23 шаблона списком и искать место для каждого. Правильнее — узнавать ситуацию и вспоминать имя хода, как шахматист узнаёт дебют.
Ключевые идеи
Шаблон — словарь команды, не KPI
Что говорит автор. Паттерн фиксирует проблему, контекст, решение и последствия. Команда, которая называет «Facade» или «Adapter», экономит десять минут рисования на доске. Цель — общий язык, а не галочка «у нас есть паттерны».
Как это выглядит в промышленном проекте. Интеграция с банком меняет API каждый квартал. Вместо «обёртка над обёрткой» на ревью говорят: «нужен Adapter с узким интерфейсом для нашего домена». Новый разработчик открывает каталог, видит структуру, не переписывает с нуля.
Как это меняется с ИИ. Модель охотно генерирует «AbstractFactory» и «Visitor» там, где хватило бы функции. Дифф выглядит «архитектурно», ревьюер устаёт и пропускает. Полезнее просить: «опиши проблему без паттерна; потом предложи один именованный ход из GoF, если он правда нужен».
Где совет может не работать. В маленькой кодовой базе и простом CRUD общий язык паттернов избыточен — достаточно ясных имён и модулей. Не каждый спор на ревью требует ссылку на GoF.
Что сделать уже сегодня. На следующем ревью спросите: «какую проблему мы решаем?» — до того, как назвали паттерн.
Мой опыт. GoF спасает в разговорах между командами и при онбординге в legacy. Когда паттерн становится целью («нам нужен Observer везде») — книга уже не помогает, мешает.
Если запомнить одну мысль — сначала проблема, потом имя из каталога.
«Программируй на интерфейс, а не на реализацию»
Что говорит автор. Зависимость от абстракции снижает связность: можно подменить реализацию, тестировать с заглушками, развивать подсистемы отдельно. Это сквозная тема creational и structural паттернов.
Как это выглядит в промышленном проекте. Сервис отправки уведомлений зависит от интерфейса Notifier, а не от конкретного SMS-шлюза. Новый канал — новая реализация, домен не перекомпилируется. Без этого каждый if (channel === 'sms') размазывает интegrацию по десяти модулям.
Как это меняется с ИИ. Ассистент генерирует «интерфейс на каждый класс» — зоопарк из одного метода. Абстракция ради абстракции. Критерий остаётся человеческим: есть ли две реализации или реальная перспектива подмены?
Где совет может не работать. YAGNI: интерфейс до второй реализации часто преждевременен. В функциональном стиле и TypeScript union types роль «интерфейса» играет тип — идея та же, форма другая.
Что сделать уже сегодня. Найдите одну зависимость от конкретного класса в зоне текущей задачи — нужна ли подмена в тестах или следующем релизе?
Мой опыт. Это, пожалуй, самая живая мысль GoF в 2026 году. Остальное — частные случаи того, как не прибить код к одной реализации.
Если запомнить одну мысль — интерфейс там, где завтра будет вторая реализация.
Композиция предпочтительнее наследования
Что говорит автор. Наследование жёстко связывает подкласс с базой; композиция (объект содержит другие объекты и делегирует) гибче. Decorator, Strategy, Bridge — про это.
Как это выглядит в промышленном проекте. «Расширить» класс отчёта наследованием для каждого нового формата (PDF, Excel, API) — взрыв иерархии. Strategy для рендерера + композиция данных отчёта — добавили формат без трогания базового класса.
Как это меняется с ИИ. Модель любит глубокие деревья наследования — «выглядит ООП». Человек должен ловить момент, когда пора заменить extends на «поле + делегирование».
Где совет может не работать. Фреймворки с lifecycle (React class components в прошлом, некоторые UI-kit) навязывают наследование. В доменном коде композиция почти всегда выигрывает у глубоких иерархий.
Что сделать уже сегодня. Откройте один extends в текущей задаче — можно ли заменить на композицию без потери ясности?
Мой опыт. GoF здесь стыкуется с рефactoringом Фаулера: «Replace Inheritance with Delegation» — не модная причуда, а следствие той же идеи.
Если запомнить одну мысль — наследование для «is-a» с стабильной семантикой; поведение через композицию.
Creational: гибкость создания, не Singleton ради Singleton
Что говорит автор. Factory Method, Abstract Factory, Builder, Prototype — про то, кто и как создаёт объекты, когда конструктор new недостаточен. Singleton — тоже creational, но с оговорками.
Как это выглядит в промышленном проекте. Builder для сложного документа с десятком опциональных полей читается лучше, чем конструктор на 14 параметров. Factory скрывает выбор реализации PaymentGateway по конфигу. Singleton для «единственного» подключения к БД в монолите — частый источник боли в тестах и при масштабировании.
Как это меняется с ИИ. Агент по умолчанию делает Singleton «для кэша» и глобальное состояние. Ревью должно резать: нужен ли один экземпляр в процессе, или это ленивая привычка.
Где совет может не работать. DI-контейнеры (Spring, Nest, Angular) уже решают создание — паттерны живут внутри фреймворка, не в вашем коде. Builder избыточен для DTO из трёх полей.
Что сделать уже сегодня. Если видите Singleton — спросите: «как мы тестируем это без глобального состояния?»
Мой опыт. Builder и Factory — самые частые живые creational-паттерны у меня. Singleton в новом коде — красный флаг, если только это не OS-level ресурс.
Если запомнить одну мысль — creational-паттерны про варианты создания, не про «красивую фабрику».
Behavioral: Strategy и Observer для изменений
Что говорит автор. Strategy инкапсулирует семейство алгоритмов и делает их взаимозаменяемыми. Observer рассылает изменения подписчикам без жёсткой связи. Command, State, Iterator — другие ответы на «как объекты общаются и меняют поведение».
Как это выглядит в промышленном проекте. Налоговые правила по странам — Strategy, а не switch на 200 строк. UI подписывается на изменение модели — Observer (или его современные формы: события, reactive streams). Без имени паттерна код превращается в «список колбеков, который нельзя отладить».
Как это меняется с ИИ. ИИ генерирует switch/case; рефакторинг в Strategy — хорошая задача для агента после тестов. Observer в микросервисах часто заменён message broker — идея «подписчики не знают друг друга» остаётся.
Где совет может не работать. Observer с сотней подписчиков в одном процессе — проблемы с порядком и утечками памяти. Strategy с одним алгоритмом — лишний слой.
Что сделать уже сегодня. Найдите один большой switch по типу или статусу — кандидат на Strategy?
Мой опыт. Strategy и Observer я узнаю в legacy чаще, чем Abstract Factory. Именно behavioral-паттерны чаще всего остаются в живом коде.
Если запомнить одну мысль — behavioral-паттерны покупают гибкость изменения поведения.
Structural: Adapter и Facade на границах
Что говорит автор. Adapter приводит чужой интерфейс к вашему. Facade даёт простой вход в сложную подсистему. Decorator добавляет обязанности без подклассов. Proxy контролирует доступ.
Как это выглядит в промышленном проекте. Старый SOAP-сервис, новый REST внутри — Adapter для домена. Facade над пятью микросервисами биллинга — один метод «выставить счёт» для фронта. Decorator для логирования и метрик вокруг репозитория — если не превращается в матрёшку.
Как это меняется с ИИ. Модель генерирует Facade, который просто пробрасывает все методы — бесполезная прослойка. Хороший Facade сужает surface area.
Где совет может не работать. Лишний Adapter, когда можно поправить контракт upstream. Decorator-цепочка из пяти слоёв — debugging hell.
Что сделать уже сегодня. На границе с внешним API нарисуйте: «наш интерфейс» vs «их интерфейс» — нужен ли Adapter?
Мой опыт. Facade и Adapter — мои рабочие лошадки в интegraциях. GoF здесь ближе всего к ежедневной работе full-stack команды.
Если запомнить одну мысль — structural-паттерны живут на границах и слоях.
На практике
На ревью
- Назван ли паттерн после описания проблемы?
- Есть ли более простое решение без нового слоя?
- Не смешаны ли «красота ООП» и реальное изменение поведения?
- Для ИИ-диффа: не раздута ли иерархия классов?
С современным стеком
React hooks, middleware, plugins — часто те же идеи, другой синтаксис. Strategy ≈ prop/callback injection. Observer ≈ pub/sub, RxJS, event emitters. Не ищите класс Observer — ищите структуру зависимостей.
Кому какая идея полезнее
| Идея | Junior | Middle | Senior |
|---|---|---|---|
| Паттерн как словарь | ★★★★ | ★★★★★ | ★★★★★ |
| Интерфейс vs реализация | ★★★★★ | ★★★★★ | ★★★★ |
| Композиция vs наследование | ★★★★ | ★★★★★ | ★★★★★ |
| Creational (Builder, Factory) | ★★★★ | ★★★★★ | ★★★★ |
| Behavioral (Strategy, Observer) | ★★★★ | ★★★★★ | ★★★★★ |
| Structural (Adapter, Facade) | ★★★★ | ★★★★★ | ★★★★★ |
Ограничения и критика
GoF стареет по примерам, не по проблемам. Паттерн-omania («у нас Visitor на три класса») хуже отсутствия каталога. Многое из книги встроено в фреймворки — вы редко пишете Iterator вручную. Functional programming и immutability ставят под вопрос некоторые ООП-решения — но идея «изолировать изменение» остаётся.
Короткое сравнение. GoF — именованные формы структуры. «Чистый код» — локальная читаемость (и спорные правила). Рефactoring — как менять форму без смены поведения. DDD — какую модель строить; GoF — как связать объекты внутри модели. Не путайте слои.
Читайте GoF как справочник и язык, не как чеклист «23 галочки в Jira».
Кому читать
Стоит, если вы проектируете модули с нетривиальной связностью, интegraциями, меняющимися правилами; если на ревью не хватает общих имён; если читаете legacy с Factory и Observer.
Можно выборочно, если вы только на фреймворке «всё из коробки» — тогда достаточно знать 5–6 паттернов из статей и этой выжимки.
Осторожно, если команда измеряет архитектуру количеством паттернов — книга вам не противник, но культура может быть.
Что сделать сегодня
- В текущем модуле назовите одну проблему и проверьте, есть ли для неё один паттерн из GoF — или хватит простого рефакторинга.
- Найдите один
switchпо типу — рассмотрите Strategy только если вариантов станет больше или тесты требуют подмены. - На ревью ИИ-диффа запретите новые иерархии классов без объяснения «какую проблему решаем».
- Откройте оригинал на одну главу (Strategy или Adapter) — сравните с вашим кодом, не с tutorial из 2010 года.

