Help us understand the problem. What is going on with this article?

[Gof]Template Methodについて

More than 3 years have passed since last update.

はじめに

 本稿はTemplate Methodについて記述します。なお、文中に使用するコードはPHP5.5を想定しています。

Template Methodとは

 Template Methodは、Gofにより定義されたデザインパターンのひとつです。クラスパターン・振る舞いに関するパターンに分類されます。
 概念的には同一でありながら細部が異なる手続き群に対し適用します。これによりコードの冗長性をなくし、またコードの再利用のためのプラットフォームが提供されます。

概要

 基底クラス(=AbstractClass)に、アルゴリズムの骨組みとなるメソッド(=template method)を定義します。template methodの内部では、いくつかの流動的要素となるステップを派生クラスの定義に委任します。派生クラス(=ConcreateClass)は、流動的要素を扱うメソッド(=primitive operation)を定義します。

標準的なコード例

template_method.php
abstract class AbstractClass
{
    final public function templateMethod(){
        $this->primitiveOperationA();

        // do something.. 共通の振る舞い

        $this->primitiveOperationB();
    }

    abstract protected function primitiveOperationA();
    abstract protected function primitiveOperationB();
}

class ConcreateClass extends AbstractClass()
{
    protected function primitiveOperationA(){
        // do something..  流動的要素となる振る舞い
    }

    protected function primitiveOperationB(){
        // do something..  流動的要素となる振る舞い    
    }
}

派生クラス拡張の制御

 オーバーライドするメソッドは、primitive operationとhook operationに分類できます。両者の意味の使い分けは以下の通りです。

  • primitive operation - オーバーライドしなければならないメソッド(=強制)
  • hook operation - オーバーライドされるかもしれないメソッド(=任意)

 PHPにおいて、primitive operationはメソッド定義にabstractキーワードを付与することで実現します。
 hook operationにはデフォルトの振る舞いを定義しておくことで、派生クラス作成者に任意の拡張ポイントを提供します。

hook_operation_example.php
// AbstractClass
abstract class abstractUser
{
    // template method
    final public function search($query){
        $query = $this->before($query);

        $result = // search..

        $result = $this->after($result);

        return $result;
    }

    // hook operations. 今回の例では、デフォルトでは何もしない
    protected function before($query){ return $query; };
    protected function after($result){ return $result; };
}

// ConcreateClass
class ConcreateUser extends AbstractUser()
{
    protected function before($query){
        // do something..    
        return $query;
    }

    protected function after($result){
        // do something..
        return $result;    
    }
}

実装上の注意点

 Template Methodを設計する際の注意点を列挙します。

各メソッドの可視性

 規定クラス、サブクラスの各メソッドの可視性に注意すべきです。

  • template methodは、オーバーライドされるべきではありません。よってfinalキーワードを付与します。
  • primitive operationは、必ずオーバーライドされるべきです。よってabstractおよびprotectedキーワードを付与します。
  • hook operationは、任意にオーバーライドされます。よってprotectedキーワードを付与します。

primitive operationの最小化

 Template Methodを設計する上での重要な目標は、primitive operationの数を最小化することです。必ずオーバーライドしなければならないメソッドが増えると、クライアントにとって扱いづらくなります。あまりにもprimitive operationが多くなる場合、template methodがSRP(:単一責任原則)に違反していないか等の検証が必要です。

派生クラスは、規定クラスに完全に依存する。

 Template Methodは流動的要素のカプセル化に継承を利用します。一方で、継承は非常に強い依存関係を生み出します。ConcreateClassは、AbstractClass#templateMethod()の内容に完全に依存するため、再利用性はありません。もしConcreateClassを再利用したい/する必要がある場合は、Strategy等ほかのパターンを検討すべきです。

関連項目

  • ハリウッドの原則
    • 逆向きの制御構造の例として、引き合いにだされる場合があります。
  • Strategy
    • 「アルゴリズムの一部を変更する」という点について一致しています。Template methodが継承を利用するのに対し、Strategyは委譲を利用します。
  • Factory Method
    • しばしばtemplate methodにより呼び出されます。

参考文献

Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away