【保存版】Template Method パターンと抽象クラスのすべて|Javaで理解する再利用性の高い設計術【コード5種付き】

Java

はじめに

Java を学習していると、必ずと言っていいほど出会う設計パターンが Template Method(テンプレートメソッド)パターン です。
多くの教材では簡単な例しか扱われませんが、実務ではもっと多くの応用があります。

Template Method を使いこなせるようになると、

  • 処理の流れを共通化できる
  • 変更しやすい拡張性の高い設計ができる
  • コードの重複を大幅に削減できる
  • 保守性が劇的に向上する

というメリットがあります。

特に Java は抽象クラスやオーバーライドが強力で、Template Method と非常に相性がよい言語 です。

この記事では、Template Method パターンの基本から、
実際に業務で使われる応用例を 3〜5 種類のコード付きで丁寧にまとめました。

さらに、Java学習に役立つ学習書籍
👉 絶対にJavaプログラマーになりたい人へ。(https://amzn.asia/d/3E1CYbv)
本格的にスキルアップしたい人向けの
👉 サイゼントアカデミー(https://academy.cyzennt.co.jp)
も紹介しています。

最後まで読むことで、Template Method を 完全に理解し実務で使えるレベル まで到達できます。


第1章:Template Method パターンとは?

Template Method パターンとは、

共通の手順(テンプレート)をスーパークラスで定義し、
その中の一部の処理だけをサブクラスで差し替えられるようにするパターン。

というものです。

構造はとてもシンプルで、

  • 処理の流れ(固定)
  • 差し替える部分(可変)

を明確に分離します。

Java の抽象クラス(abstract class)を活用すると、とても綺麗に実装できます。


第2章:Template Method の基本構造

まずは最小構成の Template Method。

public abstract class Template {
    // テンプレート(処理の流れ)を定義。final にすることで変更を禁止。
    public final void execute() {
        step1();
        step2();
        step3();
    }

    // サブクラスで必ず実装すべき抽象メソッド
    protected abstract void step1();
    protected abstract void step2();
    protected abstract void step3();
}

この流れを変えずに、一部処理だけを変更できます。


第3章:Template Method × 抽象クラスの強み

Java の抽象クラスは Template Method と非常に相性が良いです。

▼ なぜ相性が良いのか?

  • 抽象メソッドを定義できる → 必ずオーバーライドを強制できる
  • final メソッドで「流れ(テンプレート)」を固定できる
  • protected メソッドで継承クラスにのみ処理を公開できる
  • 共通処理をスーパークラスに集約できる

Java の特徴である 強固な型安全性と継承モデル が Template Method の信頼性を高めています。


第4章:ここから本番!Template Method のコード例5種類

ここから、実務・学習で頻繁に出てくる Template Method の活用例を一気に紹介します。


【サンプル1】データ処理テンプレート(王道)

▼ 概要

CSV / JSON / XML など、データ形式が違っても「処理の流れは同じ」というケース。


● 親クラス(テンプレート)

public abstract class DataProcessor {

    public final void process() {
        load();
        validate();
        transform();
        save();
    }

    private void load() {
        System.out.println("共通:データ読み込み");
    }

    protected abstract void validate();

    protected abstract void transform();

    protected void save() {
        System.out.println("共通:保存処理");
    }
}

● 子クラス(CSV)

public class CsvProcessor extends DataProcessor {

    @Override
    protected void validate() {
        System.out.println("CSV バリデーション");
    }

    @Override
    protected void transform() {
        System.out.println("CSV データ変換");
    }
}

● 子クラス(JSON)

public class JsonProcessor extends DataProcessor {

    @Override
    protected void validate() {
        System.out.println("JSON バリデーション");
    }

    @Override
    protected void transform() {
        System.out.println("JSON データ変換");
    }

    @Override
    protected void save() {
        System.out.println("JSON 用保存処理");
    }
}

【サンプル2】ゲームキャラクターの行動テンプレート


● 親クラス

public abstract class CharacterAction {

    public final void act() {
        move();
        attack();
        defense();
    }

    protected abstract void move();
    protected abstract void attack();

    protected void defense() {
        System.out.println("共通:基本防御");
    }
}

● 子クラス(戦士)

public class Warrior extends CharacterAction {

    @Override
    protected void move() {
        System.out.println("戦士が前進する");
    }

    @Override
    protected void attack() {
        System.out.println("剣で攻撃する");
    }
}

● 子クラス(魔法使い)

public class Wizard extends CharacterAction {

    @Override
    protected void move() {
        System.out.println("魔法使いが浮遊する");
    }

    @Override
    protected void attack() {
        System.out.println("魔法を唱えて攻撃する");
    }

    @Override
    protected void defense() {
        System.out.println("魔法シールドで防御する");
    }
}

【サンプル3】ファイル処理テンプレート(コピー/削除/圧縮)


● 親クラス

import java.nio.file.*;

public abstract class FileTask {

    public final void execute(Path path) throws Exception {
        before(path);
        doTask(path);
        after(path);
    }

    protected void before(Path path) {
        System.out.println("開始:" + path.toString());
    }

    protected abstract void doTask(Path path) throws Exception;

    protected void after(Path path) {
        System.out.println("完了:" + path.toString());
    }
}

● 子クラス(コピー)

public class FileCopyTask extends FileTask {

    @Override
    protected void doTask(Path path) throws Exception {
        Files.copy(path, Path.of("backup_" + path.getFileName()));
        System.out.println("コピー完了");
    }
}

● 子クラス(削除)

public class FileDeleteTask extends FileTask {

    @Override
    protected void doTask(Path path) throws Exception {
        Files.delete(path);
        System.out.println("削除完了");
    }
}

【サンプル4】ログテンプレート(環境別ログ出力)


● 親クラス

public abstract class LoggerTemplate {

    public final void log(String message) {
        String formatted = format(message);
        write(formatted);
    }

    protected String format(String message) {
        return "[LOG] " + message;
    }

    protected abstract void write(String message);
}

● 子クラス(コンソール出力)

public class ConsoleLogger extends LoggerTemplate {

    @Override
    protected void write(String message) {
        System.out.println(message);
    }
}

● 子クラス(ファイルログ)

import java.io.FileWriter;

public class FileLogger extends LoggerTemplate {

    @Override
    protected void write(String message) {
        try (FileWriter fw = new FileWriter("log.txt", true)) {
            fw.write(message + "\n");
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

【サンプル5】テスト自動化テンプレート(前処理/本処理/後処理)


● 親クラス

public abstract class TestTemplate {

    public final void runTest() {
        setup();
        test();
        tearDown();
    }

    protected void setup() {
        System.out.println("セットアップ");
    }

    protected abstract void test();

    protected void tearDown() {
        System.out.println("後処理");
    }
}

● 子クラス

public class LoginTest extends TestTemplate {

    @Override
    protected void test() {
        System.out.println("ログイン処理テスト");
    }
}

第5章:Template Method が実務で喜ばれる理由


■ ① 共通処理を一括管理できる

ログ出力、読み込み、前処理/後処理など、「どの処理にも必要な共通部分」はスーパークラスでまとめられる。


■ ② 差し替えたい部分だけ実装すればよい

サブクラスは 変わる部分にだけ集中できる
これは大規模開発では非常に強い。


■ ③ 修正に強い

「共通部分の修正」=「スーパークラスだけ修正すればよい」。
100 クラスあっても 1 箇所で済む。


■ ④ Java の抽象クラスが非常に強力

Java の継承モデルが Template Method の構造と完璧に噛み合う。


第6章:Template Method の弱点と向いていない場面


× 継承による結合度が高くなりがち

柔軟な切り替えが必要なら Strategy パターンの方が向いている。


× 手順自体が頻繁に変わる処理は向かない

Template Method はあくまで「流れを固定」するパターン。


第7章:学習の次のステップ

もし Template Method を理解できたあなたは、Java 学習の基礎がかなり固まっています。
ここから さらに強いエンジニアになるための道 が2つあります。


📘 1:まずは独学で地力をつけたい人へ

👉 絶対にJavaプログラマーになりたい人へ。
https://amzn.asia/d/3E1CYbv

Java の基礎・実践・考え方を体系的に学べる内容で、「これ一冊で土台ができる」と多くの学習者が評価しています。


🎓 2:コードレビューや転職サポートが欲しい人へ

👉 サイゼントアカデミー
https://academy.cyzennt.co.jp

初心者が最短で Java プログラマーになれるよう設計されたサポート体制が特徴。
「挫折せずに学びたい」「プロからレビューを受けたい」人に最適です。


第8章:まとめ

この記事では、Template Method パターンを中心に、

  • 基本的な概念
  • Java での実装
  • 抽象クラスの活用
  • 応用例(5種類)
  • 実務での利点
  • 注意点
  • 学習ロードマップ

まで、すべて網羅的に解説しました。

Template Method は、Java を使ううえで絶対に理解すべきパターンのひとつです。
ぜひ、このパターンを活かして 読みやすく保守しやすいコード を書いていきましょう。

コメント

タイトルとURLをコピーしました