Menu
Coddy logo textTech

Паттерн «Шаблонный метод»

Часть раздела Объектно-ориентированное программирование путешествия по PHP на Coddy. Урок 78 из 91.

Template Method Pattern — это поведенческий шаблон проектирования, который определяет каркас алгоритма в базовом class, позволяя подклассам переопределять отдельные шаги без изменения общей структуры. Базовый class управляет рабочим процессом, а подклассы настраивают отдельные части.

Рассмотрите создание разных типов документов.

Каждый документ следует одному и тому же процессу: create заголовок, добавить содержимое, create нижний колонтитул. Но конкретные детали каждого шага различаются в зависимости от типа документа. Шаблонный method определяет эту последовательность, а подклассы implement детали.

<?php
abstract class DocumentGenerator {
    // Шаблонный метод — определяет структуру алгоритма
    public final function generate(): string {
        $output = $this->createHeader();
        $output .= $this->createContent();
        $output .= $this->createFooter();
        return $output;
    }
    
    // Шаги, которые должны быть реализованы подклассами
    abstract protected function createHeader(): string;
    abstract protected function createContent(): string;
    abstract protected function createFooter(): string;
}

class HtmlDocument extends DocumentGenerator {
    protected function createHeader(): string {
        return "<html><head></head><body>";
    }
    
    protected function createContent(): string {
        return "<p>Hello World</p>";
    }
    
    protected function createFooter(): string {
        return "</body></html>";
    }
}

class TextDocument extends DocumentGenerator {
    protected function createHeader(): string {
        return "=== DOCUMENT ===\n";
    }
    
    protected function createContent(): string {
        return "Hello World\n";
    }
    
    protected function createFooter(): string {
        return "=== END ===";
    }
}

$html = new HtmlDocument();
echo $html->generate() . "\n";

$text = new TextDocument();
echo $text->generate();

Вывод:

<html><head></head><body><p>Hello World</p></body></html>
=== DOCUMENT ===
Hello World
=== END ===

Обратите внимание на ключевое слово final в шаблонном методе. Это не позволяет подклассам изменять структуру алгоритма. Паттерн идеально подходит, когда у вас есть несколько классов, которые следуют одному и тому же рабочему процессу, но отличаются деталями реализации. Добавление нового типа документа означает создание нового подкласса без изменения существующего кода.

challenge icon

Задание

Легко

Давайте создадим систему генерации отчетов с использованием паттерна «Шаблонный метод». Разные типы отчетов следуют одной и той же структуре: раздел заголовка, раздел данных и раздел сводки, но каждый тип отчета форматирует эти разделы по-своему. Шаблонный метод определит этот рабочий процесс, а подклассы настроят каждый шаг.

Вы организуете код в четырех файлах:

  • ReportGenerator.php: Создайте abstract ReportGenerator class, который определяет каркас algorithm генерации отчета. Ваш class должен:
    • Принимать заголовок отчета в своем constructor (используйте продвижение свойств constructor)
    • Иметь final public method generate(): string, который вызывает три шага в следующем order: createTitle(), createBody() и createSummary(), объединяя их результаты
    • Declare три abstract protected method, которые подклассы должны implement: createTitle(): string, createBody(): string и createSummary(): string
  • HtmlReport.php: Подключите файл ReportGenerator и создайте HtmlReport class, который extends его. Этот отчет форматирует output как HTML:
    • createTitle() возвращает "<h1>[title]</h1>"
    • createBody() возвращает "<p>Report data goes here</p>"
    • createSummary() возвращает "<footer>End of report</footer>"
  • PlainTextReport.php: Подключите файл ReportGenerator и создайте PlainTextReport class, который extends его. Этот отчет использует простое текстовое форматирование:
    • createTitle() возвращает "### [title] ###\n"
    • createBody() возвращает "Report data goes here\n"
    • createSummary() возвращает "--- End of report ---"
  • main.php: Подключите оба файла отчетов. Вы получите два входных значения: тип отчета ("html" или "text") и заголовок отчета.

    На основе типа отчета создайте appropriate report generator с given заголовком. Вызовите generate() и выведите complete отчет.

Паттерн «Шаблонный метод» гарантирует, что все отчеты следуют одной и той же трехэтапной структуре, позволяя каждому типу отчета уникальным образом форматировать свои разделы. Ключевое слово final у generate() не позволяет подклассам изменять последовательность algorithm. Они могут настраивать только отдельные шаги.

Попробуйте сами

<?php

require_once 'HtmlReport.php';
require_once 'PlainTextReport.php';

// Прочитать ввод
$reportType = trim(fgets(STDIN));
$reportTitle = trim(fgets(STDIN));

// TODO: На основе типа отчёта ("html" или "text"),
// создайте соответствующий генератор отчёта с заданным заголовком

// TODO: Вызовите generate() и выведите полный отчёт

?>
quiz iconПроверьте себя

В этом уроке есть небольшой тест. Начните урок, чтобы ответить на вопросы и сохранить прогресс.

Все уроки раздела Объектно-ориентированное программирование

Потренируйтесь самостоятельно: Онлайн-компилятор PHP