Processingで学ぶ 実践的プログラミング専門課程

第26回デザインパターン(4) Template Method

導入

経験豊富な上司は、部下に仕事の枠組みを伝えます。部下はその仕事を達成するために具体的な作業をします。多くの場合、仕事はいくつもの部分に分かれていますから、複数の部下がそれぞれの部分を担当します。上司はそれらの部分的な仕事の順番のコントロールや、連絡調整を行い、全体として一つの仕事にします。

こうして一つの部署Aが仕事を行うのですが、この仕事を与え、指示したのは、さらに上の部署Bです。上の部署Bは、部署Aの社員に直接指示をしません。指示は部署Aの長A0に伝え、A0から結果を受け取ります。

組織が業務をシンプルに行っていくために、たどり着いたこの仕組み。今回学習するコードの仕組みは、ちょうどこれとよく似ています。シンプルですが、高度な仕組みです。

デザインパターンの学習の最終回となる今回は、Template Methodパターンを取り上げます。

展開

Template Method(テンプレート メソッド)

Template Methodパターンは比較的簡単なデザインパターンです。簡単で、コードに適用しやすい優れたデザインパターンですが、実は抽象的で高度な技術的判断力を必要とします。

Template Methodパターンの目的

Templateという単語は、型板、テンプレートという意味があります。テンプレートを使うと紙の上にテンプレートの形に沿った図形を描くことができます。Template Methodパターンはテンプレートの働きと似た仕組みです。AbstractClassの持つtemplateMethodはこれから行う処理の手順の枠組み、つまり型板の役割を果たします。ペンや鉛筆の役割を果たすConcreteClassの各メソッドを用い、さらにTemplate Methodパターンを用いるコード、これが紙に相当し、ここにおいて完全な形をとります。Template Methodパターンは、同じ手順で行う作業にバリエーションが欲しい場合に有効です。

私は、Template Methodパターンは、Strategyパターンで実装されるコードの共通部分を抽出し、スーパークラスにまとめたのだと考えるようにしています。ですから、Strategyパターンを使用していて、⁠これはstrategyMethod内に共通の手順があるぞ。そして抽象化してとり出せるぞ」と感じられれば、Template Methodパターンに移行します。このようなシナリオを心に留めておくと、適切なデザインパターン適用のチャンスをつかむことができるでしょう。

[Template Methodパターン]
スーパークラスには抽象化した処理の手順を持たせる。サブクラスが処理の具体的なコードを持つ。同じ手順に従う、異なった結果を生むサブクラスを作成できる。

Template Methodパターンのクラス図
画像

Template Methodパターンは、AbstractClassでサブクラスの実装するべきメソッド(method1, 2, 3)のシグニチャを宣言します。そして、AbstractClassでは、method1, 2, 3を適切な方法と手順で呼び出すtemplateMethodを実装します。AbstractClass内でmethod1, 2, 3は実装されていませんから、AbstractClassのtemplateMethodを呼んでも具体的に動作することはできません。具体的な動作は、ConcreteClassの実装によります。

AbstractClassを継承するConcreteClassの実装によって、具体的なオブジェクトの動作にバリエーションが生まれます。さらにはAbstractClassに定義されているtemplateMethodによって、ConcreteClassの利用方法が単純化されます。別の見方をすると、複数のConcreteClassで実装されている共通した手順をAbstractClassに抽出することで、ConcreteClassのコードを単純化できるのです。

Template Methodパターンを使う

それでは、Template Methodパターンを利用した、ごく簡単なサンプルコードを示します。このサンプルコードは、入力文字列に対して大文字・小文字の変換処理を行った後に、前後に装飾を加えて返します。どんな変換をし、どんな装飾を加えるかはサブクラスで実装し、変換や装飾の手順のみがスーパークラスで実装されています。

以下にsketch各ファイルへのリンクを示します。

コードの主要部分を示します。

主となるsketch Example_TemplateMethod.pde
void setup(){
  String INPUT_DATA = "HoGe";
  
  println("Original Data  : " + INPUT_DATA);
  
  AbstractClass ac = new ConcreteClass1();
  println(ac.templateMethod(INPUT_DATA));
  
  ac = new ConcreteClass2();
  println(ac.templateMethod(INPUT_DATA));
}

まず、クラスAbstractClassのオブジェクトacConcreteClass1のオブジェクト参照がセットされます。 そしてスーパークラスに実装されているtemplateMethodが呼ばれ、これを通じてサブクラスの各メソッドが呼び出されます。戻り値をprintlnが受け取ってコンソールに表示します。

次に全く同じ手順が繰り返されます。全く同じtemplateMethodが同じ引数で呼ばれます。ただし、acが持つオブジェクト参照はConcreteClass2のものです。先ほどとは手順が同じでも異なる具体的な処理が施され、文字列がコンソールに出力されます。

AbstractClassでは、

  • 大文字小文字どちらかにそろえ、前後に装飾を加えるmethod1
  • 与えられた文字列の前後に各種のカッコをつけるmethod2
  • 最後にConcreteClassのクラス名を文字列の先頭に加えるmethod3

以上のメソッドのシグニチャが宣言されます。

AbstractClassに宣言された各メソッドのシグニチャ
  public abstract String method1(String val);
  public abstract String method2(String val);
  public abstract String method3(String val);

そして一定である手順templateMethodがAbstractClassにまとめられてています。

AbstractClassに実装されたメソッドtemplateMethod
  public final String templateMethod(String val){
    return method3(method2(method1(val)));
  }

ConcreteClassではそれぞれのメソッドの実装のみを受け持ち、コードの重複が避けられ、結果としてシンプルになっています。

Strategyパターンとの比較

Template MethodパターンはStrategyパターンとよく似ています。違いは、Strategyパターンでは、主となるsketchから呼ばれるメソッドstrategyMethodが、スーパークラスに当たるインターフェイスで宣言されており、さらにそれがサブクラスに当たるクラス(以後、実装クラスと呼びます)で実装されることです。インターフェイスのstrategyMethodが呼ばれ、それはそのまま実装クラスのstrategyMethod呼び出しとなります。これは、実際の処理を実装クラスに「委譲」⁠いじょう)していると言います。

Template Methodパターンでは、主となるsketchから呼ばれるメソッドtemplateMethodは、スーパークラスでのみ宣言・実装されています。主となるsketchからよばれたtemplateMethodは、サブクラスに実装されている各メソッドを呼び出します。主となるsketchから見ると、サブクラスにはないメソッドをサブクラスのオブジェクトに対して呼んでいます。これは、実際の処理をサブクラスが「継承」していると言います。

Template Methodパターンは簡単か?


Template Methodパターンはこれまでに紹介したデザインパターン(Facade,Iterator,Strategy)と比較して、とてもシンプルなパターンです。クラス図も簡単です。スーパークラスとサブクラスしか現れません。よく似ているStrategyパターンとクラス図を比べると特にそう感じられるでしょう。しかし、実際にこれらのデザインパターンを使う状況の頻度は、Strategyパターンの方が多いでしょう。そして、問題への適用もしやすいでしょう。私はこの違いを、Template Methodパターンが問題から「抽象的な手順」を抽出しているからだと考えています。異なる「具体的な手順」を抽出するのは比較的簡単です。しかし、それぞれの手順から抽象的な共通部分を見出すのは高度な技術です。

デザインパターンの最終回を飾るものとして、適用の難易度から考えると、このTemplate Methodパターンが適切ではないかと考えました。いかがだったでしょうか。

演習

演習1(難易度:easy)

  1. ディスプレイウインドウに図形を表示するクラスを、Template Methodパターンで実装しましょう。

以下の条件で作成してください。

  • AbstractClasstemplateMethodに図形の位置と大きさを指定すると、その場所に図形を表示する。
  • ConcreteClass1は、外形線の太さが4、塗りつぶし色は赤の円を描きます。
  • ConcreteClass2は、外形線の太さが10、塗りつぶし色は青の正方形を描きます。
  • ディスプレイウインドウのサイズは(400,400)、丸の位置は(100,200)、大きさ50、正方形の位置は(300,200)、大きさ50とします。
実行時のスクリーンショット
画像

まとめ

  • Template Methodパターンとは何かを学びました。
  • Template Methodパターンの使い方を学びました。

学習の確認

それぞれの項目で、Aを選択できなければ、本文や演習にもう一度取り組みましょう。

  1. Template Methodパターンとは何かがわかりましたか?
    1. 分かった。自分のプログラミングにも使いたい。
    2. どんなものかを理解することはできたが、活用シーンが思いつかない。
    3. 本文が理解できない。
  2. Template Methodパターンを使えるようになりましたか?
    1. 使えるようになった。自分のプログラミングにも活用できそうだ。
    2. 本文の例を理解することはできたが、自分のプログラミングに活用できる気がしない。
    3. 本文の例が理解できない。

参考文献

  • 『増補改訂版Java言語で学ぶデザインパターン入門』⁠結城浩 著、ソフトバンククリエイティブ
    • 誰もが認める最も分かりやすいデザインパターン入門書。
  • 『オブジェクト指向における再利用のためのデザインパターン』⁠Eric Gamma 著、ソフトバンククリエイティブ
    • デザインパターンの原典。別称『GoF本⁠⁠。
  • 『Java デザインパターン徹底攻略』⁠日立ソフトウェアエンジニアリング⁠株⁠インターネットビジネス部 著、技術評論社
    • 前掲のGoF本の解説書で、サンプルはJava言語。絶版。強く再版を望みます。

演習解答

  1. コード例を示します。

    Template Methodにそってクラスが作成されていることを際立たせるために、クラス名をパターンの解説そのままにしています。しかしがなら、図形を表示する、という仕事であることを明示する名称の方が、実際のコードでは優先されるべきです。例えば、AbstractClassShapeDrawerConcreteClass1RedCircleWithBoldLineなどとしたほうが適切です。また、各メソッド名も仕事を明確に表す名称であるべきです。例えば、templateMethoddrawShapeや単にdrawなどとします。応用課題として、自分の作成したコードについて、そのようなリファクタリングを施してみましょう。その際、これらのコード群がTemplate Methodパターンを使用していることを、どこかに一言コメントするか、クラス名・メソッド名にそれを示す単語を含めておくと良いでしょう。後になって、これらのクラスの関係が不明になってしまうことを避けるためです。

    コメントにTemplate Methodパターンを使用していることを明示しておく。
    public abstract class AbstractClass{
      // Template Methodパターンを使用しています。
      (以下略)

おすすめ記事

記事・ニュース一覧