本文へスキップ
BecomeCoder

Javaデザインパターンコース · 第4章 振る舞いに関するパターン ― オブジェクト同士の「連携の仕方」を工夫する · レッスン11

Template Method ― 手順の骨格は固定し、一部だけ変える

ブラウザで完結

導入

コーヒーも紅茶も、作り方の大まかな流れ(お湯を沸かす → 抽出する → カップに注ぐ)は同じで、違うのは「抽出する」の中身だけです。この共通の流れを毎回書き直すのは無駄です。Template Method(テンプレートメソッド) は、処理の骨格を親クラスで固定し、変わる部分だけを子クラスに任せる パターンです。

説明

親クラス(抽象クラス)が「決まった順番で呼び出す」骨格メソッドを持ち、その中の一部だけを abstract にして子クラスに実装させます。

public class Main {
    public static void main(String[] args) {
        Drink coffee = new Coffee();
        coffee.prepare();

        Drink tea = new Tea();
        tea.prepare();
    }
}

abstract class Drink {
    final void prepare() {
        boilWater();
        brew();
        pourInCup();
    }

    void boilWater() {
        System.out.println("お湯を沸かす");
    }

    abstract void brew();

    void pourInCup() {
        System.out.println("カップに注ぐ");
    }
}

class Coffee extends Drink {
    void brew() {
        System.out.println("コーヒーを抽出する");
    }
}

class Tea extends Drink {
    void brew() {
        System.out.println("紅茶を蒸らす");
    }
}
classDiagram
  Drink <|-- Coffee
  Drink <|-- Tea
  class Drink {
    <<abstract>>
    +prepare() final
    +boilWater()
    +brew()* abstract
    +pourInCup()
  }
  • final void prepare() { boilWater(); brew(); pourInCup(); } … これが「手順の骨格」です。final を付けて、子クラスがこの順番自体は上書きできないようにしています。
  • abstract void brew(); … 「抽出する」の中身だけは子クラスごとに違うので、抽象メソッドにして子クラスに実装を強制します。
  • CoffeeTea はそれぞれ brew() だけをオーバーライドします。boilWater()pourInCup() は共通実装のまま何も書かずに使われます。
  • coffee.prepare() を呼ぶと、Drink に書かれた順番通りに実行され、brew() の部分だけ Coffee の実装(コーヒーを抽出する)に動的に差し替わって呼ばれます(第1章オブジェクト指向コースで学んだ動的束縛の応用です)。

やってみよう

下のエディタを実行し、CoffeeTea でそれぞれ「お湯を沸かす」「カップに注ぐ」が共通で、間の一行だけが違うことを確認しましょう。

演習

Juice という Drink のサブクラスを作り、brew() をオーバーライドして ジュースを絞る と表示させてください。mainDrink juice = new Juice(); juice.prepare(); を呼んでください。

ヒント1を見る

class Juice extends Drink { void brew() { System.out.println("ジュースを絞る"); } }

ヒント2を見る

boilWater()pourInCup() はオーバーライドしなくても、Drink の実装がそのまま使われます。

実際に動かしてみよう

下のエディタにJavaを書いて「実行」を押すと、学習用シミュレータが System.out.println の出力を表示します(本物のJVMではなく、教材の範囲を再現した軽量エンジンです)。クラス・継承・コレクションなども動きます。Scanner で入力を読む例は「標準入力」欄に値を入れてください。本文の例を書き換えて動かしてみましょう(Stream・ラムダ・スレッド・ファイル入出力など一部の機能は対象外です)。

Java — ブラウザ内で実行(学習用シミュレータ)

Javaの教材サブセットを動かす学習用シミュレータを読み込みます(本物のJVMではなく、動きを再現した軽量な自作エンジンです)。
スクロールして表示された時点でも自動で読み込まれます。