デザインパターン[GoF 23]#3 TemplateMethodパターン

こんにちは!ぐちです。

〜ぼっちAdvent Calendar風イベント実施中[13日目]〜

先日、大事なことに気づきました。今僕が実施している「ぼっちAdvent Calendar風イベント」ですが、Avent Calendarというのはそもそも12月25日までの取り組みなんです!過去の記事でもご説明したのですが、なぜに僕が実施しているイベントは12月31日までと宣言してしまったのでしょうか。。。いや、まあ、あれですよ・・・誰もやってないことを自ら進んで取り組・・・すいません!!!勘違いしただけです!

はい、ということで、今回は下記の記事三つ目をご紹介したいと思います。

TemplateMethodパターン

これは名称よりもコードを見て頂いたほうがピンッとくる方が多いかもしれませんが、非常によく見かけるデザインパターンです。

端的にご説明しますと「具体的な処理をサブクラスで定義し、処理の流れの大枠は親クラスで決めておく。」といったものです。ある大きな処理を複数のステップに分割し、ステップの実行順序は守りつつも、各ステップ内の処理はサブクラスに決めさせることができます。

まずは枠組み(テンプレートメソッド)を定義するクラスです。

public abstract class TemplateMethod {
     protected abstract void process1();

     protected abstract void process2();

     protected abstract void process3();

     public final void mainProcess() {
          process1();
          for (int i = 0; i < 5; i++) {
               process2();
          }
          process3();
     }
}

抽象メソッドを定義し、具体的な処理はサブクラスに任せるためにabstractを定義します。処理の枠組みを定義するためにmainProcessメソッドに具体的な処理の流れ”のみ”を定義します。

続いてprocess1〜process3までの”具体的な”処理を記述するクラスを定義します。四角を表示するクラスと星を表示するクラスにします。

public class StarDisplay extends TemplateMethod {
     @Override
     protected void process1() {
          System.out.print("START ☆");
     }

     @Override
     protected void process2() {
          System.out.print("★");
     }

     @Override
     protected void process3() {
          System.out.println("☆ END");
     }
}

こちらが星を表示するクラスですね。TemplateMethodクラスを継承しています。

次に四角を表示するクラスです。

public class SquareDisplay extends TemplateMethod {
     @Override
     protected void process1() {
          System.out.print("START □");
     }

     @Override
     protected void process2() {
          System.out.print("■");
     }

     @Override
     protected void process3() {
          System.out.println("□ END");
     }
}

このように、各サブクラスで異なる処理だけを実装させるようにすることで、必要なものだけ局所的にオーバーライドすることが可能です。

使い方としては以下のようにすることで枠組みの処理の流れは変わらずに実行することができます。

public class Main {
     public static void main(String[] args) {
          TemplateMethod proc1 = new StarDisplay();
          TemplateMethod proc2 = new SquareDisplay();

          proc1.mainProcess();
          proc2.mainProcess();
     }
}

もうひとつのポイントとしては親クラスの型で変数を定義することです。そうすることによってmainProcessメソッド(枠組みの処理)を呼び出すことが可能です。

注意点

どの処理をどれくらいの粒度でメソッド分けするのかをしっかり考えないと使い勝手が悪くなったり、オーバーライドできずに余計に手間がかかる可能性があります。

サンプルコード

GitHubにアップしていますのでご自由にお使いください。

では今回はこの辺で。

2016年振り返り

以前、投稿した北見出張の際に、北見工業大学で行われたハッカソンにファシリテーターとして参加させてもらいました。ハッカソンというもの自体に初めて参加したのでファシリテートもくそもないかと不安でしたが、うまく進められました。まず思い浮かぶ感想は「学生さんってめっちゃアツい!」ですね。目がキラキラ輝いていて、人懐っこく各企業のファシリテーターに相談してくるあたりなんて、ほんと感動を覚えるレベルでした。僕もああいう時期があったんだなと思うと、もっと頑張らないといけないなと感じました。若い子たちからパワーをもらえた非常に良いハッカソンだったと思います。ちなみに僕がファシリテートさせてもらったチームは・・・入賞ならずでした。笑

ぼっちAdvent Calendar風ルール

  • 1日1記事更新する
  • 記事内に1年間の出来事の振り返りを1つ明記する
  • 1日の期間は起きてから寝るまで(時刻ではない)

ぼっちAdvent Calendar風イベントとは?下記の記事をご覧ください。