Template Method
Паттерн «скелет алгоритма»: общая последовательность шагов фиксируется в базовом классе, а отдельные шаги переопределяют подклассы.
Template Method определяет скелет алгоритма в методе базового класса, оставляя реализацию отдельных шагов подклассам.
Какую задачу решает
Несколько алгоритмов отличаются лишь парой шагов, а каркас одинаков: «загрузить данные → обработать → сохранить». Копировать каркас в каждый класс — дублирование. Template Method фиксирует порядок в базовом классе (template-метод), а изменчивые шаги объявляет абстрактными — их заполняют наследники.
Идея и реализация
from abc import ABC, abstractmethod
class Report(ABC):
def generate(self): # template-метод: скелет фиксирован
self.load()
body = self.format()
self.save(body)
def load(self):
print("Загружаю данные")
@abstractmethod
def format(self): ...
def save(self, body):
print("Сохраняю:", body)
class HtmlReport(Report):
def format(self):
return "<h1>Отчёт</h1>"
class TextReport(Report):
def format(self):
return "ОТЧЁТ"
HtmlReport().generate()
TextReport().generate()
Вывод:
Загружаю данные Сохраняю: <h1>Отчёт</h1> Загружаю данные Сохраняю: ОТЧЁТ
Метод generate задаёт неизменный порядок шагов. Подклассы переопределяют только format — изменчивую часть. Шаги load/save общие и не дублируются. Это «инверсия управления»: базовый класс вызывает методы подкласса, а не наоборот (принцип «не звоните нам, мы позвоним вам»).
Полезный приём — «хуки» (hooks): необязательные шаги с пустой реализацией по умолчанию, которые подкласс может переопределить, а может проигнорировать. Например, добавим в базовый класс пустой метод before_save() и вызовем его в шаблоне перед сохранением. Подклассу, которому нужна предобработка, достаточно его переопределить; остальные ничего не замечают. Так каркас остаётся жёстким там, где важна структура, и гибким там, где нужна вариативность.
Главный риск Template Method — жёсткость наследования. Подкласс намертво привязан к базовому классу и его порядку шагов; поменять алгоритм целиком в рантайме нельзя, а глубокие иерархии быстро становятся хрупкими. Поэтому, если изменчивых шагов много и они независимы, часто выгоднее собрать поведение из стратегий (композиция), а Template Method приберечь для случаев с одним-двумя варьируемыми шагами и стабильным каркасом.
Template Method против Strategy
| Template Method | Strategy |
| Через наследование | Через композицию |
| Меняет шаги алгоритма | Меняет алгоритм целиком |
| Фиксируется в подклассе | Подменяется в рантайме |
Где встречается
Базовые классы фреймворков (жизненный цикл View/компонента с хуками), пайплайны обработки данных, методы тестов (setUp/tearDown вокруг вашего теста), алгоритмы сортировки с переопределяемым сравнением.
Итог
- Template Method фиксирует скелет алгоритма, отдавая шаги подклассам.
- Убирает дублирование общего каркаса; реализует инверсию управления.
- В отличие от Strategy, работает через наследование, а не композицию.