デザインパターン入門 | Template Method(テンプレートメソッド)パターン
「Template Method(テンプレートメソッド)」パターンは、継承を利用した「処理の共通化」を行うことができるデザインパターンです。
今回は「ガソリンスタンド」を事例に「Template Method(テンプレートメソッド)」パターンについてご説明をしていきたいと思います。
「Template Method(テンプレートメソッド)」パターンの概要
今回の事例で扱う「ガソリンスタンド」に共通している処理として、「給油」があります。
「給油」の処理の流れは、概ね
- 給油する燃料の選択
- 給油作業
- 燃料代金の支払い
という流れになります。
継承元となる親クラスを「AbstractGasStation」抽象クラスとして作成します。
このクラスには、
- selectFuelType
- 「給油」する燃料を選択する抽象メソッド
- reFueling
- 「給油」を行う抽象メソッド
- payFuelBill
- 「燃料代金」を支払う抽象メソッド
が定義されています。
そしてもう一つ、これらのメソッドを利用して処理の流れを決めている「reFuelingCar」メソッドが定義されています。
package SampleTemplateMethod; public abstract class AbstractGasStation { public abstract String selectFuelType(); public abstract void reFueling(String fuelType); public abstract void payFuelBill(String fuelType); public final void reFuelingCar() { String fuelType = selectFuelType(); reFueling(fuelType); payFuelBill(fuelType); } }
そして、この「AbstractGasStation」クラスを継承する先のクラスですが、「ガソリンスタンド」には「給油スタッフが常駐している」タイプと「セルフ給油を行う」タイプの「ガソリンスタンド」があります。
「給油スタッフが常駐している」タイプのGSのクラスは、「NormalGasStation」クラスとして作成します。
package SampleTemplateMethod; public class NormalGasStation extends AbstractGasStation { @Override public String selectFuelType() { String fuelType = "ガソリン"; System.out.println("給油する燃料は" + fuelType + "と給油スタッフに伝えました。"); return fuelType; } @Override public void reFueling(String fuelType) { System.out.println(fuelType + "を給油スタッフが給油しました。"); } @Override public void payFuelBill(String fuelType) { System.out.println(fuelType + "代金を給油スタッフに支払いました。"); } }
そして、「セルフ給油を行う」タイプのGSは「SelfGasStation」クラスとして作成します。
package SampleTemplateMethod; public class SelfGasStation extends AbstractGasStation { @Override public String selectFuelType() { String fuelType = "ガソリン"; System.out.println("給油機で" + fuelType + "を給油燃料として選択しました。"); return fuelType; } @Override public void reFueling(String fuelType) { System.out.println(fuelType + "を自分で給油しました。"); } @Override public void payFuelBill(String fuelType) { System.out.println(fuelType + "代金を給油機で支払いました。"); } }
どちらのクラスも「selectFuelType・reFueling・payFuelBill」メソッドの具体的な処理を実装していますが、それぞれのタイプのスタンドごとに内容が異なっていることが読み取れますね。
これらのメソッドを利用する「main」メソッドは下記のようになります。
package SampleTemplateMethod; public class Main { public static void main(String[] args) { System.out.println("【給油スタッフ常駐のGS】"); AbstractGasStation gs1 = new NormalGasStation(); gs1.reFuelingCar(); System.out.println(""); System.out.println("【セルフ形式のGS】"); AbstractGasStation gs2 = new SelfGasStation(); gs2.reFuelingCar(); } }
「NormalGasStation・SelfGasStation」クラスのインスタンスを作り、親クラスである「AbstractGasStation」クラスが定義している「reFuelingCar」メソッドを実行しています。
処理の流れはこの「reFuelingCar」メソッドで定義されているため、このメソッドが「処理のテンプレート」的な役割を行っているため、このメソッドを「テンプレートメソッド」と呼ぶことがあります。
そして、実行結果は下記のようになります。
【給油スタッフ常駐のGS】 給油する燃料はガソリンと給油スタッフに伝えました。 ガソリンを給油スタッフが給油しました。 ガソリン代金を給油スタッフに支払いました。 【セルフ形式のGS】 給油機でガソリンを給油燃料として選択しました。 ガソリンを自分で給油しました。 ガソリン代金を給油機で支払いました。
「Template Method(テンプレートメソッド)」パターンを使えるようになることで、「テンプレートメソッド」を修正するだけで、継承先のクラスに影響を与えることなく、処理のパターンを変更できるようになります。
仕組み自体もシンプルで、デザインパターンの中でも比較的使いやすいパターンですので、ぜひ使えるようになっていきましょう。