DPDesign Pattern Quest
パターン一覧/Template Method
#22 / 23
B振る舞いDIFF

テンプレートメソッド

Template Method

レシピは同じ手順、具材だけが違う。親が骨格を握り、子が肉付けを担当する。

Intent · 目的

アルゴリズムの『流れ』は親クラスの中で固定し、変動する『各ステップの中身』はサブクラスでオーバーライドさせる。手順は一箇所に書かれ、肉付けは派生クラスごとに変えられる。

Motivation · 動機

「データを取ってきて → 整形して → 出力する」── この流れは JSON レポートでも CSV レポートでも同じ。違うのは『どこから取るか』『どう整形するか』だけ。それぞれを丸ごとコピペで2つ書くと、流れの修正のたびに両方を直すことになる。Template Method なら親に流れを書き、変動する2ステップだけサブクラスに任せる。料理本のレシピに例えるなら、「肉を切る」→「炒める」→「煮込む」の流れは共通、肉と調味料だけ違う、というようなもの。

適用場面

  • 1アルゴリズムの全体手順は同じだが、特定のステップだけ実装が違う場面(レポート、テスト基盤、ゲームAIの行動ループ)。
  • 2コードの重複を排除したいフレームワーク的な使い方。
  • 3サブクラスでの拡張ポイントを明示したい場合。

概念図

サンプルコード

abstract class ReportGenerator {
  generate(): string {
    const raw = this.fetch();
    const body = this.format(raw);
    return this.decorate(body);
  }
  protected abstract fetch(): string;
  protected abstract format(raw: string): string;
  protected decorate(body: string){ return "=== Report ===\n" + body; }
}

class JsonReport extends ReportGenerator {
  protected fetch(){ return JSON.stringify({ x: 1 }); }
  protected format(raw: string){ return "JSON: " + raw; }
}

console.log(new JsonReport().generate());
Pros · メリット
  • アルゴリズム共通の流れが1か所に集約され、コピペが消える。
  • ステップごとの拡張ポイントが明確で、サブクラス作成のガイドが効く。
  • 親の流れを修正すれば、全サブクラスの挙動が一気に揃う。
Cons · デメリット
  • 親クラスを変更すると全サブクラスに影響する。継承の鎖はそういうもの。
  • Strategy のように実行時に差し替えられない(型レベルで決まる)。
  • サブクラス側で意図せず親メソッドを上書きすると、リスコフ置換違反を起こしやすい。

関連パターン

⚔ ready to test

理解度を確かめる時間だ

3 問のクイズで、 このパターンを身体に染み込ませよう。

挑戦する →