Увійти Реєстрація
Блог Серії
Кар'єра
Вакансії Компанії
Навчання
Документація Співбесіди Тестування Відео
Екосистема
Пакети Ресурси Проєкти Інструменти Події
Інше
Про нас Реклама

Чим Template Method відрізняється від Strategy і коли що обрати?

Обидва патерни розв'язують одну задачу - змінювати частину алгоритму, не змінюючи загальної структури. Різниця - у механізмі.

Template Method - через успадкування. Базовий клас задає скелет алгоритму, а змінні кроки - абстрактні методи для нащадків:

abstract class DataImport
{
    final public function run(string $path): ImportResult
    {
        $rows = $this->read($path);                   // змінний крок
        $valid = array_filter($rows, $this->validate(...));
        $this->persist($valid);                       // змінний крок
        return new ImportResult(count($valid), count($rows) - count($valid));
    }

    abstract protected function read(string $path): array;
    abstract protected function validate(array $row): bool;
    abstract protected function persist(array $rows): void;
}

final class ProductImport extends DataImport { /* реалізує три кроки */ }

Strategy - через композицію. Змінна частина - окремий об'єкт, переданий ззовні:

final class DataImport
{
    public function __construct(
        private RowReader $reader,
        private RowValidator $validator,
        private RowWriter $writer,
    ) {}

    public function run(string $path): ImportResult { /* той самий скелет */ }
}

Порівняння:

Template Method Strategy
механізм успадкування композиція
коли обирається варіант при створенні класу (компіляція) при створенні об'єкта (виконання)
комбінування варіантів новий підклас на кожну комбінацію будь-яка комбінація об'єктів
доступ до стану нащадок бачить protected батька лише через параметри й інтерфейс
тестування кроків через підклас кожна стратегія окремо

Коли Template Method доречний:

  • скелет стабільний, варіантів небагато, кроки тісно пов'язані між собою;
  • фреймворк визначає життєвий цикл, а ви заповнюєте «гачки»: Command::handle(), Seeder::run(), Notification::via()/toMail() у Laravel, setUp() у тестах - усе це шаблонні методи;
  • кроки потребують спільного стану базового класу.

Коли Strategy:

  • варіанти комбінуються незалежно (формат × доставка × кешування);
  • варіант обирається під час виконання (за налаштуваннями, типом користувача);
  • кроки корисно тестувати й повторно використовувати окремо.

Еволюція: часто код починається з Template Method (простіше), а коли комбінацій стає багато - рефакториться в Strategy («замінити успадкування делегуванням»). final на методі-скелеті в Template Method важливий - нащадки не повинні змінювати порядок кроків.

Докладніше в документації: Refactoring.Guru: Template Method

Перевір себе

20 випадкових питань за спробу, після завершення - розбір кожної помилки

Схожі питання