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でデザインパターン(番外編:Intercepting Filterパターン)

zip形式 tgz形式

PHPでGoFのデザインパターンを実装するシリーズ(?)の番外として、J2EEパターンでもPHPで使えるかな?と思ったパターンを実装してみました。

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

今回は、Intercepting Filterパターンで、「複数の小粒度なコンポーネントを柔軟に追加・削除できる」パターンです。

Chain of Responsibility編の時にひろしさん@PHPカイハツ旧サイトのBBSに書き込んでいらっしゃいますが、その中の「Filterパターン」が気になってSunのサイトなどを調べてみていると、Java World 2001年12月号の「J2EEパターン」特集でやってましたので、それを参考にやってみました。ちなみに、Intercepting Filterは、Java World誌にも説明がありますが、Decorating Filterという名前だったようです(識者の方、レスお願いします(^-^;)。

まず、クラス図ですが、大まかには以下のようになります。

Intercepting Filterパターンのクラス図

使い方としては、1つずつの処理(フィルタ)をFilterクラス(Javaならinterface)のサブクラスとして用意し、それらをまとめるFilterChainオブジェクトに登録します。そして、これをFilterManagerオブジェクトに登録し、フィルタの処理を実行させるためのメソッド(今回はprocessFilterメソッド)を実行します。んー。。。どことなくChain of Responsibilityに似ていると思うのは私だけでしょうか。。。

今回のサンプルは、Chain of Responsibility編で作った「与えられた文字がどんな文字種かどうかを調べるもの」を使ってみました。Chain of Responsibilityと異なり、フィルタとして登録された全ての処理を順次処理を行います。実行結果を比べていただくと分かると思います。また、abstractメソッドの実装を強制させるためのクラスも使用しています。

ということで、以下がサンプルコードです。Abstract.phlを含めたスクリプトコードは、上のリンクからダウンロードできます。

今回はサンプルを使い回しているので分かりづらいですが、本来はページ表示の前処理(例えば認証と権限設定)・後処理(例えば結果のロギングなど)などの小さな処理が連続して起こる場面に適応できるようです。また、サンプル中ではフィルタをベタ書きしていますが、外部の設定ファイルなどで定義できるようにしておくと、設定ファイルの修正だけで動作を変えることができるようになります。

●InterceptingFilter.php

<?php
require_once("Abstract.phl");
class Filter
{
    /**
     * 抽象メソッド。
     */
    function execute($variable) { Abstract::set("execute"); }

}

class FilterManager
{
    var $filterChain_;

    function FilterManager($filters)
    {
        $this->filterChain_ = new FilterChain();
        if (!is_array($filters)) {
            $filters = array($filters);
        }
        foreach ($filters as $idx => $filter) {
            $this->filterChain_->addFilter($filter);
        }
    }

    function processFilter($variable)
    {
        $this->filterChain_->execute($variable);
    }
}

class FilterChain
{
    var $next_;

    function FilterChain()
    {
        $this->next_ = array();
    }

    /*
     * フィルタの追加
     */
    function addFilter($next){
        array_push($this->next_, $next);
    }

    /**
     * 処理の実行。これを呼び出す
     */
    function execute($variable)
    {
        reset($this->next_);
        foreach ($this->next_ as $idx => $obj) {
            echo " =>" . get_class($obj) . "が処理中。。。";
            if ($obj->execute($variable)) {
                echo "<font color=\"red\"><b>これ!</b></font>";
            }
            echo "<BR>";
        }
    }

}

/**
 * 具体的な処理を定義するクラス(フィルタ)
 */

class NumberFilter extends Filter
{
    function execute($variable)
    {
        return preg_match("/^[0-9]+$/", $variable);
    }
}
class AlphabetFilter extends Filter
{
    function execute($variable)
    {
        return preg_match("/^[a-z]+$/i", $variable);
    }
}
class MobileNumberFilter extends Filter
{
    function execute($variable)
    {
        return preg_match("/^0[0-9]0-[0-9]{4}-[0-9]{4}$/", $variable);
    }
}
?>
<?php
    /**
     * main
     */
    $filters = array(new NumberFilter(), new AlphabetFilter(), new MobileNumberFilter());
    //$filters = new NumberFilter();
    $filterManager = new FilterManager($filters);

    /**
     * 動作のチェック
     */
    doIt($filterManager, "090-1234-5678");
    doIt($filterManager, "09012345678");
    doIt($filterManager, "chain_of_responsibility");
    doIt($filterManager, "ChainOfResponsibility");
    doIt($filterManager, "abc123");
?>
<?php
    function doIt($fm, $target)
    {
        echo "<hr>●target=" . $target . "<br>";
        $fm->processFilter($target);
    }
?>

●出力結果
●target=090-1234-5678
 =>numberfilterが処理中。。。
 =>alphabetfilterが処理中。。。
 =>mobilenumberfilterが処理中。。。これ!

●target=09012345678
 =>numberfilterが処理中。。。これ!
 =>alphabetfilterが処理中。。。
 =>mobilenumberfilterが処理中。。。

●target=chain_of_responsibility
 =>numberfilterが処理中。。。
 =>alphabetfilterが処理中。。。
 =>mobilenumberfilterが処理中。。。

●target=ChainOfResponsibility
 =>numberfilterが処理中。。。
 =>alphabetfilterが処理中。。。これ!
 =>mobilenumberfilterが処理中。。。

●target=abc123
 =>numberfilterが処理中。。。
 =>alphabetfilterが処理中。。。
 =>mobilenumberfilterが処理中。。。
  


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