テンプレートパターン
テンプレートパターン(Template Pattern)では、抽象クラスがそのメソッドを実行する方法/テンプレートを公開定義します。そのサブクラスは必要に応じてメソッドの実装をオーバーライドできますが、呼び出しは抽象クラスで定義された方法で行われます。このタイプのデザインパターンは、振る舞い型パターンに属します。
紹介
意図
親クラスでアルゴリズムの骨格を定義し、サブクラスがアルゴリズムの構造を変更せずに、アルゴリズムの特定のステップを再定義できるようにします。
主に解決する問題
- 複数のサブクラスで同じメソッドを繰り返し実装する問題を解決し、共通メソッドを親クラスに抽象化することでコードの重複を避けます。
使用シーン
- 複数のサブクラスで共用できる共通のメソッドが存在する場合。
実装方法
- 抽象親クラスを定義する:テンプレートメソッドといくつかの抽象メソッドまたは具象メソッドを含みます。
- サブクラスを実装する:抽象親クラスを継承し、抽象メソッドを実装します。アルゴリズムの構造は変更しません。
重要なコード
- テンプレートメソッド:抽象親クラスで定義され、抽象メソッドと具象メソッドを呼び出します。
- 抽象メソッド:サブクラスによって実装され、アルゴリズムの可変部分を表します。
- 具象メソッド:抽象親クラスで実装され、アルゴリズムの不変部分を表します。
応用例
- 建築プロセス:基礎工事、配線、配管などのステップは同じですが、後期の建築(クローゼットの追加、フェンスの設置など)のステップは異なります。
- 西遊記の81難:菩薩が定めた81難は、トップレベルの論理的な骨格を表します。
- SpringによるHibernateのサポート:トランザクションの開始、Sessionの取得、Sessionのクローズなどの共通メソッドをカプセル化しています。
長所
- 不変部分のカプセル化:アルゴリズムの不変部分が親クラスにカプセル化されています。
- 可変部分の拡張:サブクラスはアルゴリズムの可変部分を拡張または変更できます。
- 共通コードの抽出:コードの重複を減らし、メンテナンスを容易にします。
短所
- クラス数の増加:異なる実装ごとにサブクラスが必要となり、システムが肥大化する可能性があります。
使用上のアドバイス
- 複数のサブクラスに共通するメソッドがあり、ロジックが同じ場合は、テンプレートメソッドパターンの使用を検討してください。
- 重要または複雑なメソッドについては、親クラスにテンプレートメソッドとして定義することを検討できます。
注意事項
- 悪意のある変更を防ぐために、テンプレートメソッドは通常
finalfinalキーワードで修飾され、サブクラスによるオーバーライドを防ぎます。
含まれるいくつかの主要な役割
-
抽象親クラス(Abstract Class):
- テンプレートメソッドといくつかの抽象メソッドまたは具象メソッドを定義します。
-
具象サブクラス(Concrete Classes):
- 抽象親クラスを継承し、抽象メソッドを実装します。
-
フックメソッド(Hook Method)(オプション):
- 抽象親クラスで定義され、サブクラスがオーバーライドしてテンプレートメソッドの動作に影響を与えることができます。
-
クライアント(Client)(オプション):
- 抽象親クラスと具象サブクラスを使用し、テンプレートメソッドの詳細を気にする必要はありません。
実装
操作を定義するGame抽象クラスを作成します。ここでは、テンプレートメソッドがfinalに設定されているため、オーバーライドされません。CricketとFootballは拡張したGameエンティティクラスであり、抽象クラスのメソッドをオーバーライドします。
TemplatePatternDemo、デモクラスは使用してGameテンプレートパターンの使用方法をデモンストレーションします。
ステップ 1
抽象クラスを作成し、そのテンプレートメソッドをfinalに設定します。
Game.java
public abstract class Game {
abstract void initialize();
abstract void startPlay();
abstract void endPlay();
//テンプレート
public final void play(){
//ゲームの初期化
initialize();
//ゲームの開始
startPlay();
//ゲームの終了
endPlay();
}
}
ステップ 2
上記のクラスを拡張したエンティティクラスを作成します。
Cricket.java
public class Cricket extends Game {
@Override
void endPlay() {
System.out.println("Cricket Game Finished!");
}
@Override
void initialize() {
System.out.println("Cricket Game Initialized! Start playing.");
}
@Override
void startPlay() {
System.out.println("Cricket Game Started. Enjoy the game!");
}
}
Football.java
public class Football extends Game {
@Override
void endPlay() {
System.out.println("Football Game Finished!");
}
@Override
void initialize() {
System.out.println("Football Game Initialized! Start playing.");
}
@Override
void startPlay() {
System.out.println("Football Game Started. Enjoy the game!");
}
}
ステップ 3
使用してGameのテンプレートメソッド play() でゲームの定義方法をデモンストレーションします。
TemplatePatternDemo.java
public class TemplatePatternDemo {
public static void main(String[] args) {
Game game = new Cricket();
game.play();
System.out.println();
game = new Football();
game.play();
}
}
ステップ 4
プログラムを実行し、結果を出力します:
Cricket Game Initialized! Start playing. Cricket Game Started. Enjoy the game! Cricket Game Finished! Football Game Initialized! Start playing. Football Game Started. Enjoy the game! Football Game Finished!その他の拡張