Do You PHP?    
Search Engine Optimization  php5 powerd  Valid XHTML 1.0!  Valid CSS!  このサイトのはてなブックマーク数 



last updated
2005/05/30

counter hits
since 1999/11/06


PHP4でデザインパターン(Chain of Responsibility編)

オブジェクト指向についてはまだまだ勉強中ですが、「PHPでGoFのデザインパターンを実装したら、どんな感じになるんだろ?」と思ってしまったので、ちょっとずつやってみることにしました。

caution間違いやご意見がありましたら、遠慮なくツッコミを入れてくださいm(_"_)m

今回は、Chain of Responsibilityパターンで「複数のオブジェクトをチェーンにしておき、目的のオブジェクトを決定させる」パターンです(以下のクラス図を参照)。

Chain of Responsibilityパターンのクラス図

今回のサンプルは、与えられた文字がどんな文字種かどうかを調べるものです。具体的には以下の3つになります。

  • 数字のみ
  • アルファベット(大文字小文字)
  • 携帯電話番号(xxx-xxxx-xxxx)

これらをConcreteHandlerとして用意しました。上のクラス図との関係は、以下のようになります。

  • Handler => CheckHander
  • ConcreteHander => NumberCheckHandler/AlphabetCheckHandler/MobileNumberCheckHandler

ということで、以下がサンプルコードです。

●ChainOfResponsibility.php

<?php
class CheckHandler
{
    var $next_;

    /**
     * 次に実行されるクラスのセッター
     */
    function &setNext(&$next)
    {
        $this->next_ = $next;
        return $this->next_;
    }

    /**
     * 確認用のゲッター
     */
    function getNext()
    {
        return $this->next_;
    }

    /**
     * 処理の実行。これを呼び出す
     */
    function check($variable)
    {
        if ($this->checked($variable)) {
            echo $variable . ":checked by " . get_class($this) . "<BR>";
        }
        else if (isset($this->next_)) {
            $this->next_->check($variable);
        }
        else {
            echo $variable . ":unknown<BR>";
        }
    }

    /**
     * 実際の処理を行うメソッド。抽象的な位置づけ
     */
    function checked($variable)
    {
    }
}

class NumberCheckHandler extends CheckHandler
{
    function checked($variable)
    {
        return preg_match("/^[0-9]+$/", $variable);
    }
}
class AlphabetCheckHandler extends CheckHandler
{
    function checked($variable)
    {
        return preg_match("/^[a-z]+$/i", $variable);
    }
}
class MobileNumberCheckHandler extends CheckHandler
{
    function checked($variable)
    {
        return preg_match("/^0[0-9]0-[0-9]{4}-[0-9]{4}$/", $variable);
    }
}
?>
<?php
    /**
     * main
     */
    $ch = new CheckHandler();
    $cn = new NumberCheckHandler();
    $ca = new AlphabetCheckHandler();
    $cm = new MobileNumberCheckHandler();

    /**
     * 処理チェーンの作成。Javaのように、
     * ch.setNext(cn).setNext(ca).setNext(cm)と書けないようだ。。。
     *
     * また、参照渡し・参照受けにする必要がある
     */
    $cn =& $ch->setNext(&$cn);
    $ca =& $cn->setNext(&$ca);
    $cm =& $ca->setNext(&$cm);

    /**
     * セットされているかチェック
     */
    $tmp = $ch->getNext();
    echo "\$tmp=".get_class($tmp)."<br/>";
    $tmp = $tmp->getNext();
    echo "\$tmp=".get_class($tmp)."<br/>";
    $tmp = $tmp->getNext();
    echo "\$tmp=".get_class($tmp)."<br/>";
    $tmp = $tmp->getNext();
    echo "\$tmp=".get_class($tmp)."<br/>";

    /**
     * 動作のチェック
     */
    $ch->check("090-1234-5678");
    $ch->check("09012345678");
    $ch->check("chain_of_responsibility");
    $ch->check("hoge");
?>

●出力結果
$tmp=checknumber
$tmp=numbercheckhandler
$tmp=alphabetcheckhandler
$tmp=mobilenumbercheckhandler
$tmp=
090-1234-5678:checked by mobilenumbercheckhandler
09012345678:checked by numbercheckhandler
chain_of_responsibility:unknown
hoge:checked by alphabetcheckhandler
  

Javaでは処理チェーンを作成するときに「ch.setNext(cn).setNext(ca).setNext(cm)」のような感じで書けるのですが、PHPでは「parse error」になってしまいます。んー。残念。。。なお、setNextメソッドのメソッドの引数・戻り値は参照での受け渡しとなります

memo[2002/02/28] メソッドではなくコンストラクタでチェーンを作成するバージョンを、ひろしさん@PHPカイハツ旧サイトのBBSに書いています。そちらも参照してみてください。

また、今回は実際のチェック処理メソッド(checked)をHandlerで定義、ConcreteHandlerで実装していますが、Compositeパターンの時にも書いたとおり、Javaのabstractようにメソッドのオーバーライドが強制されないので、実装側で注意が必要です。

memo[2002/03/09] こちらに「abstractメソッドの実装を強制」させることについてまとめています



About This Site |  Privacy Policy |  Contact
Copyright © 1999 - 2005 by Hideyuki SHIMOOKA all rights reserved.