|
zip形式
tgz形式
PHPでGoFのデザインパターンを実装するシリーズ(?)の番外として、J2EEパターンでもPHPで使えるかな?と思ったパターンを実装してみました。
間違いやご意見がありましたら、遠慮なくツッコミを入れてくださいm(_"_)m
今回は、Intercepting Filterパターンで、「複数の小粒度なコンポーネントを柔軟に追加・削除できる」パターンです。
Chain of Responsibility編の時にひろしさん@PHPカイハツが旧サイトのBBSに書き込んでいらっしゃいますが、その中の「Filterパターン」が気になってSunのサイトなどを調べてみていると、Java World 2001年12月号の「J2EEパターン」特集でやってましたので、それを参考にやってみました。ちなみに、Intercepting Filterは、Java World誌にも説明がありますが、Decorating 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
$filters = array(new NumberFilter(), new AlphabetFilter(), new MobileNumberFilter());
$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が処理中。。。
|