Menu
Coddy logo textTech

Template Methodパターン

CoddyのPHPジャーニー「オブジェクト指向プログラミング」セクションの一部。レッスン 78/91。

テンプレートメソッドパターンは、base class で algorithm の骨格を defines する振る舞いに関するデザインパターンであり、全体の構造を変更せずに、サブクラスが特定の手順をオーバーライドできるようにします。base class がワークフローを制御し、サブクラスが個々の部分をカスタマイズします。

さまざまな種類のドキュメントの構築を考えてみましょう。

すべてのドキュメントは同じプロセスに従います:create ヘッダー、コンテンツの追加、create フッター。ただし、各ステップの具体的な内容はドキュメントの種類によって異なります。テンプレートメソッドがこの順序を定義し、サブクラスが詳細を 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 ===

テンプレート method の final キーワードに注目してください。これにより、サブクラスが algorithm の構造を変更できなくなります。このパターンは、同じワークフローに従いながら実装の詳細が異なる複数の class がある場合に最適です。新しいドキュメントタイプを追加するには、既存のコードに手を加えずに新しいサブクラスを作成します。

challenge icon

チャレンジ

簡単

テンプレートメソッドパターンを使用して、レポート生成システムを構築しましょう。異なる種類のレポートは、タイトルセクション、データセクション、概要セクションという同じ構造に従いますが、各レポートタイプはこれらのセクションを異なる方法でフォーマットします。テンプレートメソッドでこのワークフローを定義し、サブクラスで各ステップをカスタマイズします。

コードを4つのファイルに分けて整理します。

  • ReportGenerator.php:レポート生成アルゴリズムの骨格を定義する抽象 ReportGenerator class を Create します。class には次の要件があります。
    • constructor でレポートのタイトルを受け取る(constructor promotion を使用する)
    • final な public method generate(): string を持ち、3つのステップ、createTitle()createBody()createSummary() をこの order で Call し、それらの結果を連結する
    • サブクラスが implement する必要がある、3つの abstract な protected methods、createTitle(): stringcreateBody(): stringcreateSummary(): string を Declare する
  • HtmlReport.php:ReportGenerator ファイルを含め、それを extends する HtmlReport class を Create します。このレポートは output をHTMLとしてフォーマットします。
    • createTitle()"<h1>[title]</h1>" を返す
    • createBody()"<p>Report data goes here</p>" を返す
    • createSummary()"<footer>End of report</footer>" を返す
  • PlainTextReport.php:ReportGenerator ファイルを含め、それを extends する PlainTextReport class を Create します。このレポートはシンプルなテキストフォーマットを使用します。
    • createTitle()"### [title] ###\n" を返す
    • createBody()"Report data goes here\n" を返す
    • createSummary()"--- End of report ---" を返す
  • main.php:両方のレポートファイルを含めます。2つの入力、レポートタイプ("html" または "text")とレポートタイトルを受け取ります。

    レポートタイプに Based して、given のタイトルで appropriate なレポート generator を Create します。generate() を Call し、complete なレポートを出力します。

テンプレートメソッドパターンにより、各レポートタイプがそれぞれのセクションを独自にフォーマットできる一方で、すべてのレポートが同じ3ステップの構造に従うことが保証されます。generate()final keyword により、サブクラスがアルゴリズムの順序を変更することを防ぎます。サブクラスは個々のステップのみをカスタマイズできます。

自分で試してみよう

<?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オンラインコンパイラ