Y's note

Web技術・プロダクトマネジメント・そして経営について

本ブログの更新を停止しており、今後は下記Noteに記載していきます。
https://note.com/yutakikuchi/

TemplateMethod パターン

概要

親クラスに共通処理の流れを記述し、子クラスで各処理の具体的な実装を行うパターンです。
メリットとしては共通処理を一箇所にまとめることができるのと、子クラスで具体的な実装が組めるのでやりたい処理をクラスごとに変更することができます。
処理の方が決まっているクラス、例えばAPIクラス(パラメータ取得して、DBに接続して、結果を返してなど)などの定義では必ずと言っていいほど
使われているような気がします。

ハリウッドの原則

これはちょっと面白い話です。TemplateMethodパターンは通常とは"逆"のメソッド呼び出しをします。というのも抽象クラスから子クラスが
呼び出されるためです。この状態を示す英文として[ Don't call us. We'll call you ] 我々を呼び出すな、必要なときは我々が君を呼び出す という言葉があるようです。
ここでの我々は抽象クラス、君は子クラスという意味になりますね。誰が考えたのかわかりませんが、ユーモアを感じますね。

抽象クラス

<?php

abstract class APIModel {

    protected $_params = array();
    protected $_method = null;

    protected function __construct() {}
    protected function __destruct() {}

    protected function prepare() {
        //DBの初期化処理を記述 ※別クラス化
    }

    protected function getParams() {
        $this->_params = $_REQUEST;
    }

    public function fetch() {
        $this->getParams();
        $this->validate();
        $this->prepare();
        $this->execute();
        $result = $this->parse();
        $this->tearDown();
        return $result;
    }

    protected function tearDown() {
        //DBの開放処理などを記述
    }


}

共通処理の流れをfetchに書きました。これにより処理の流れを定義できます。その他のprotected関数については子クラスで詳細定義を行ないます。

継承クラス

<?php
class TestAPI extends APIModel {
   
    public function __construct() {}
    public function __destruct() {}

    protected function prepare() {
        //初期化処理を行ないます。
        parent::prepare();
    }

    protected function validate() {
        //パラメータのvalidateを行ないます。
        $ret = true;
        if( $ret === false ) {
            throw new Exception();
        }
    }

    protected function execute() {
        //DBに接続するなど実行を行ないます。
        $this->_data = array( 'Test' );
    }

    protected function parse() {
        //結果の整形
        array_push( $this->_data, 'API');
        return $this->_data;
    }

    protected function tearDown() {
        //後処理を行ないます。※DBの開放など
    }

}

class SampleAPI extends APIModel {

    public function __construct() {}
    public function __destruct() {}
    
    protected function prepare() {
        //初期化処理を行ないます。
        parent::prepare();
        
    }

    protected function validate() {
        //パラメータのvalidateを行ないます。
        echo "aaaa \n"; 
    }

    protected function execute() {
        //DBに接続するなど実行を行ないます。
        $this->_data = array( 'Sample' );
    }

    protected function parse() {
        //結果の整形
        array_push( $this->_data, 'API');
        return $this->_data;
    }

    protected function tearDown() {
        //後処理を行ないます。※DBの開放など
    }

}

親クラスで抽象化されていたメソッドの詳細定義を行っています。クライアントから利用される時は親クラスのfetchを呼び出します。

client

<?php

//client 
try {
  $test = new TestAPI();
  $data = $test->fetch();
  print_r( $data );

  $sample = new SampleAPI();
  $data = $sample->fetch();
  print_r( $data );
} catch( Exception $e ) {
    exit;
}

インスタンス化するクラスを切り替えて実行します。それぞれのクラスで詳細定義したメソッドを抽象クラスが呼び出しているので、処理の流れが共通ですが
結果が異なります。

実行結果

Array
(
    [0] => Test
    [1] => API
)
aaaa 
Array
(
    [0] => Sample
    [1] => API
)