Template Method — Шаблонный метод
Последовательность шагов алгоритма фиксирована в базовом классе. Наследники переопределяют отдельные шаги. Основа Transaction Script.
Проблема
Несколько вариантов одной бизнес-операции (платёж: внутренний, международный, крипто). Каждый требует одинаковых шагов (валидация → авторизация → перевод → нотификация), но конкретная реализация шагов разная.
Не хочется дублировать последовательность во всех вариантах.
Решение
- Базовый класс задаёт последовательность шагов в одном методе.
- Каждый шаг — отдельный метод (
validate,authorize, ...). - По умолчанию шаги бросают
throw new Error('not implemented')или имеют дефолтную реализацию. - Наследники переопределяют нужные шаги, не трогая последовательность.
Пример в JS
// Базовый класс с фиксированной последовательностью
class MoneyTransfer {
async process(request, connection) {
await this.validate(request);
await this.authorize(request);
await this.transfer(request, connection);
await this.notify(request);
}
validate(r) { throw new Error('not implemented'); }
authorize(r) { throw new Error('not implemented'); }
transfer(r, c) { throw new Error('not implemented'); }
notify(r) { /* дефолт: ничего не делать */ }
}
class DomesticTransfer extends MoneyTransfer {
validate(r) { /* ... */ }
authorize(r) { /* ... */ }
transfer(r, c) { /* SQL UPDATE accounts ... */ }
}
class InternationalTransfer extends MoneyTransfer {
validate(r) { /* + проверка санкций */ }
authorize(r) { /* + 3DS */ }
transfer(r, c) { /* + SWIFT */ }
notify(r) { /* отправить email */ }
}
// Функциональная альтернатива без наследования
const workflow = (steps) => async (request) => {
for (const step of steps) await step(request);
};
const moneyTransfer = workflow([validate, authorize, transfer, notify]);
const internationalTransfer = workflow([validateIntl, authorize3DS, transferSwift, notifyEmail]);
Где используется в JS-экосистеме
- Express middleware-цепочки — последовательность обработчиков (но это уже антипаттерн в 2026, по автору)
- NestJS interceptors + pipes + guards — фиксированная последовательность по фазам
- React lifecycle —
componentDidMount,componentDidUpdate(template method класса) - Hooks порядок — фиксирован, нарушать нельзя
- Тестовые фреймворки:
beforeEach,it,afterEach
Подводные камни
- Template Method = жёсткая последовательность — если порядок меняется, паттерн ломается.
- Глубокое наследование становится непрозрачным — что унаследовано, что переопределено.
- Альтернатива в JS — функциональный pipe из шагов (без наследования).
- Связь с транзакциями: «весь template-метод обернуть в транзакцию» — рекомендация автора.
Главные тезисы автора
- «Определение шагов алгоритма».
- «Последовательность задана в корне, её уже не можем трогать» — это и суть, и ограничение.
- «Каждый шаг можно переопределить» в наследниках.
- «Дефолтное поведение + переопределение» — шаги по умолчанию
throwили логируют. - Template Method + persistent state — основа Transaction Script.
- Транзакция: секунды, не часы — длительность блокировок.
- В JS — функциональная альтернатива через массив функций без наследования.
- Object pool коннекшенов прокидывается во все шаги.
🎓 Источники
- 🎓 Patterns Transaction Script и Template Method · 2025-12-18
- MoneyTransfer как абстрактный класс
- Шаги по дефолту throw
- Иерархия наследников (Domestic, International, Crypto)
- Транзакция вокруг template-метода
- Функциональная реализация без наследования
- 🎓 GoF Patterns Обзор всех паттернов · 2025-04-29