Паттерн Шаблонный метод (Template Method) в PHP

Короткий скринкаст: паттерн «Шаблонный метод» (Template Method) — задаёт скелет алгоритма, делегируя детали подклассам. На примере приготовления чая и кофе.

Template Method Pattern — открыть страницу урока

Описание

Шаблонный метод определяет общий порядок действий в алгоритме, оставляя реализацию некоторых шагов подклассам. Базовый абстрактный класс CaffeineBeverage содержит метод prepareRecipe(), помеченный как final — это и есть шаблонный метод. Общие шаги (boilWater, pourInCup) реализованы в базовом классе, а отличающиеся (brew, addCondiments) объявлены абстрактными. Подклассы Tea и Coffee реализуют только свои вариации этих шагов.

UML-диаграмма

classDiagram class CaffeineBeverage { <<abstract>> +prepareRecipe(): void #boilWater(): void #pourInCup(): void #brew(): void #addCondiments(): void } class Tea { #brew(): void #addCondiments(): void } class Coffee { #brew(): void #addCondiments(): void } CaffeineBeverage <|-- Tea CaffeineBeverage <|-- Coffee

Код

CaffeineBeverage.php

abstract class CaffeineBeverage
{
    final public function prepareRecipe(): void
    {
        $this->boilWater();
        $this->brew();
        $this->pourInCup();
        $this->addCondiments();
    }

    protected function boilWater(): void
    {
        echo "Boiling water\n";
    }

    protected function pourInCup(): void
    {
        echo "Pouring into cup\n";
    }

    abstract protected function brew(): void;

    abstract protected function addCondiments(): void;
}

Tea.php

class Tea extends CaffeineBeverage
{
    protected function brew(): void
    {
        echo "Steeping the tea\n";
    }

    protected function addCondiments(): void
    {
        echo "Adding lemon\n";
    }
}

Coffee.php

class Coffee extends CaffeineBeverage
{
    protected function brew(): void
    {
        echo "Dripping coffee through filter\n";
    }

    protected function addCondiments(): void
    {
        echo "Adding sugar and milk\n";
    }
}

demo.php

require_once 'CaffeineBeverage.php';
require_once 'Tea.php';
require_once 'Coffee.php';

$tea = new Tea;
$tea->prepareRecipe();

echo "\n";

$coffee = new Coffee;
$coffee->prepareRecipe();

Пример результата

Boiling water
Steeping the tea
Pouring into cup
Adding lemon

Boiling water
Dripping coffee through filter
Pouring into cup
Adding sugar and milk

Преимущества

  • Избегается дублирование кода: общий алгоритм хранится в одном месте.
  • Подклассы переопределяют только то, что действительно отличается.
  • Легко расширять, не меняя структуру алгоритма.
  • Контролирует последовательность шагов.

Когда использовать

  • Когда у нескольких классов есть общий алгоритм, но шаги различаются.
  • Когда нужно избежать дублирования кода в подклассах.
  • Когда важно зафиксировать порядок выполнения шагов.
  • Когда некоторые шаги обязательны для всех подклассов.

Использование в Laravel

В Laravel шаблонный метод часто встречается в абстрактных классах и трейтах. Например, в миграциях базовые классы задают порядок действий, а разработчик переопределяет детали. Также в сервис-провайдерах и в некоторых пакетах используются абстрактные классы с шаблонным методом для унификации поведения.