1
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

【GoFデザインパターン】Template Method(テンプレートメソッド)パターンをJavaで理解する

1
Last updated at Posted at 2026-10-02

はじめに

本記事は、GoFデザインパターン解説シリーズの1つです。

今回は、振る舞いに関するパターンの中のTemplate Method(テンプレートメソッド)パターンを解説します。

前回解説したStrategyパターンと似た目的を持ちながら、継承をベースにしている点が特徴のパターンです。

解決したい課題

「処理全体の大まかな流れは同じだが、一部のステップだけが処理内容によって異なる」という場面があります。

例えば、「データを読み込み→処理し→出力する」という一連のバッチ処理があり、対象データがCSVファイルの場合とデータベースの場合とで、「読み込み」「出力」の具体的な処理内容だけが異なるとします。

これを何も考えずに実装すると、CsvBatchProcessorとDatabaseBatchProcessorのような別々のクラスに、「処理全体の流れ」を表すコードまで重複してコピーされてしまうことになりがちです。

全体の流れに変更(例えば「処理」と「出力」の間に「検証」ステップを追加する)が必要になった場合、すべての重複箇所を漏れなく修正しなければなりません。

Template Methodパターンは、「処理全体の流れ(骨格)」を親クラスに1箇所だけ定義し、変化する部分だけをサブクラスに実装させることで、この問題を解決します。

image.png

クラス構成

  • AbstractClass(抽象クラス): 処理全体の流れ(テンプレートメソッド)を定義する抽象クラス。個別のステップの一部は、サブクラスに実装を委ねる抽象メソッドとして宣言する
  • ConcreteClass(具体的なクラス): AbstractClassを継承し、抽象メソッドの部分だけを具体的に実装するクラス

image.png

Javaでの実装例

先ほどのバッチ処理の例で実装してみます。

AbstractClass:処理全体の流れを定義する抽象クラス

public abstract class BatchProcessor {

    // これがテンプレートメソッド。全体の処理の流れ(骨格)を1箇所に定義し、finalで変更を禁止する
    public final void execute() {
        System.out.println("=== バッチ処理開始 ===");
        Object data = loadData();       // サブクラスに委ねる
        Object processed = processData(data); // サブクラスに委ねる
        validate(processed);            // 共通処理(サブクラスでは変更不可)
        outputData(processed);          // サブクラスに委ねる
        System.out.println("=== バッチ処理完了 ===");
    }

    protected abstract Object loadData();
    protected abstract Object processData(Object data);
    protected abstract void outputData(Object data);

    // 共通のステップは、親クラスに実装を持たせることもできる(サブクラスでの上書き不要)
    private void validate(Object data) {
        System.out.println("[共通処理] データを検証しました");
    }
}

ConcreteClass:CSVファイルを扱う場合の実装

public class CsvBatchProcessor extends BatchProcessor {
    @Override
    protected Object loadData() {
        System.out.println("[CSV] ファイルからデータを読み込みました");
        return "csv-data";
    }

    @Override
    protected Object processData(Object data) {
        System.out.println("[CSV] データを加工しました: " + data);
        return "processed-" + data;
    }

    @Override
    protected void outputData(Object data) {
        System.out.println("[CSV] 加工済みデータをファイルに出力しました: " + data);
    }
}

ConcreteClass:データベースを扱う場合の実装

public class DatabaseBatchProcessor extends BatchProcessor {
    @Override
    protected Object loadData() {
        System.out.println("[DB] データベースからデータを読み込みました");
        return "db-data";
    }

    @Override
    protected Object processData(Object data) {
        System.out.println("[DB] データを加工しました: " + data);
        return "processed-" + data;
    }

    @Override
    protected void outputData(Object data) {
        System.out.println("[DB] 加工済みデータをデータベースに書き戻しました: " + data);
    }
}

利用側のコード

public class Main {
    public static void main(String[] args) {
        BatchProcessor csvProcessor = new CsvBatchProcessor();
        csvProcessor.execute();

        System.out.println();

        BatchProcessor dbProcessor = new DatabaseBatchProcessor();
        dbProcessor.execute();
    }
}

実行結果:

=== バッチ処理開始 ===
[CSV] ファイルからデータを読み込みました
[CSV] データを加工しました: csv-data
[共通処理] データを検証しました
[CSV] 加工済みデータをファイルに出力しました: processed-csv-data
=== バッチ処理完了 ===

=== バッチ処理開始 ===
[DB] データベースからデータを読み込みました
[DB] データを加工しました: db-data
[共通処理] データを検証しました
[DB] 加工済みデータをデータベースに書き戻しました: processed-db-data
=== バッチ処理完了 ===

処理全体の流れ(「読み込み→加工→検証→出力」という順序)は、BatchProcessor#execute()という1箇所のみに定義されており、final修飾子によってサブクラスでの上書きも禁止されています。

CsvBatchProcessorとDatabaseBatchProcessorは、それぞれ異なるべき「読み込み方法」「加工方法」「出力方法」の3つのメソッドだけを実装しています。

今後、全体の流れに新しいステップを追加したくなった場合も、execute()を1箇所修正するだけで、すべてのサブクラスに反映されます。

Strategyパターンとの違い

前回解説したStrategyパターンと、Template Methodパターンは、どちらも「アルゴリズムの一部を切り替え可能にする」という目的では共通していますが、実現方法が異なります。

観点 Template Method Strategy
実現方法 継承(サブクラスでメソッドをオーバーライド) コンポジション(戦略オブジェクトを外部から注入)
変更の柔軟性 コンパイル時に決まる(実行時の切り替えは基本不可) 実行時に自由に切り替え可能
クラス間の結合度 親クラスとサブクラスが密結合になりやすい Contextと戦略オブジェクトは疎結合

「継承よりコンポジションを優先せよ」という設計原則の観点から、近年は同じ課題に対してStrategyパターンが好まれる傾向もありますが、「処理の骨格を1箇所に固定し、変更を防ぎたい」という意図が明確な場合は、Template Methodパターンが今でも有効です。

image.png

使用場面

  • 複数のクラスで、処理の大まかな流れ(骨格)は共通だが、一部のステップだけが異なる場合
  • フレームワークが処理の骨格を提供し、利用者側に一部の処理だけをカスタマイズさせたい場合(多くのフレームワークの拡張ポイント設計で使われる)
  • 処理順序を厳密に固定し、サブクラス側で処理順序自体を変更できないようにしたい場合

まとめ

項目 内容
解決する課題 処理全体の流れは共通だが、一部のステップだけが異なる処理の重複を防ぎたい
実現方法 処理全体の流れを親クラスのテンプレートメソッドに定義し、変化する部分だけをサブクラスに実装させる
メリット 全体の流れの変更が1箇所で完結し、サブクラスは差分のみ実装すればよい
Strategyとの違い Template Methodは継承ベース(コンパイル時固定)、Strategyはコンポジションベース(実行時切り替え可能)

おすすめ書籍

GoFの23パターンをより深く学びたい方には、以下の書籍がおすすめです。
Java言語のサンプルコードとUMLを使い、初心者にもわかりやすく解説されています。

Java言語で学ぶデザインパターン入門 第3版 [ 結城 浩 ]

※本リンクはアフィリエイトリンクを含みます。

参考

1
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?