|
zip形式
tgz形式
オブジェクト指向についてはまだまだ勉強中ですが、「PHPでGoFのデザインパターンを実装したら、どんな感じになるんだろ?」と思ってしまったので、ちょっとずつやってみることにしました。
間違いやご意見がありましたら、遠慮なくツッコミを入れてくださいm(_"_)m
今回は、Visitorパターンで「データ構造と処理を分離する」パターンです(以下のクラス図を参照)。Visitorがデータ構造をトレースしながら処理を行っていきます。
今回のサンプルは、Compositeパターンの時に使った「組織と所属メンバーのツリー構造」を使いました。Compositeパターンの時は、データを表すEntryクラスの中にデータを表示するメソッドprintTreeがありましたが、Visitorパターンを使うとこれを分離する事ができます。作ってみて思ったのは、「実際の動作は結構複雑」だったことです。。。私は頭が煮えそうでした。。。(-"-;
さて、以下がサンプルコード(抜粋)になります。コード内部でiteratorクラスを使っていますが、「abstractメソッドの実装を強制する」でお世話になった黒木さんがphp-usersで投稿されたIteratorクラスを使わせていただいています。やっぱり、便利だ。。。(^-^)
また、printVisitorクラスのvisitメソッドでは、渡された$entryの型(DeptなのでEmpなのか)によって、再帰処理を実行するかどうかを判断しています。ちなみに、Javaではvisitメソッドをオーバーロードさせるでしょうね。
●Visitor.php
<?php
class Acceptor extends Object
{
function accept($visitor) { Abstract::set(); }
}
:
class Dept extends Entry
{
var $entry_;
:
function iterator()
{
return new Iterator($this->entry_);
}
function accept($visitor)
{
$visitor->visit($this);
}
}
class Emp extends Entry
{
:
function accept($visitor)
{
$visitor->visit($this);
}
}
class Visitor extends Object
{
function visit($entry) { Abstract::set(); }
}
class printVisitor
{
function visit($entry)
{
echo $entry->getId() . ":" . $entry->getName() . "<br>\n";
if ($entry->instanceOf("Dept")) {
$iter = $entry->iterator();
while ($iter->hasNext()) {
$obj = $iter->next();
$obj->accept($this);
}
}
}
}
class Iterator {
var $stKeys = array() ;
var $iIndex = 0 ;
var $aArray = array() ;
function Iterator( &$aArray ) {
if( is_array( $aArray ) ) {
$this->stKeys = array_keys( $aArray ) ;
$this->aArray = &$aArray ;
}
}
function hasNext() {
if( $this->iIndex < count( $this->stKeys ) ) return true ; else return false ;
}
function next() {
if( $this->iIndex < count( $this->stKeys ) ) {
$stKey = $this->stKeys[ $this->iIndex ] ;
$this->iIndex++ ;
return $this->aArray[$stKey] ;
} else {
return false ;
}
}
}
?>
<?php
$root = new Dept("001", "本社");
$root->add(new Emp("00101", "シャチョー"));
$root->add(new Emp("00102", "ブチョー"));
$dept1 = new Dept("010", "○○支店");
$dept1->add(new Emp("01001", "支店長"));
$dept1->add(new Emp("01002", "佐々木さん"));
$dept2 = new Dept("110", "△△営業所");
$dept2->add(new Emp("11001", "下岡さん"));
$dept1->add($dept2);
$root->add($dept1);
$dept3 = new Dept("020", "××支店");
$dept3->add(new Emp("02001", "畑さん"));
$dept3->add(new Emp("02002", "緒方さん"));
$root->add($dept3);
echo "●本社からのツリー<br>\n";
$root->accept(new printVisitor());
echo "<br>\n";
:
?>
●出力結果(当然Compositeの時と同じ)
●本社からのツリー
001:本社
00101:シャチョー
00102:ブチョー
010:○○支店
01001:支店長
01002:佐々木さん
110:△△営業所
11001:下岡さん
020:××支店
02001:畑さん
02002:緒方さん
●○○支店からのツリー
010:○○支店
01001:支店長
01002:佐々木さん
110:△△営業所
11001:下岡さん
●△△営業所からのツリー
110:△△営業所
11001:下岡さん
●××支店からのツリー
020:××支店
02001:畑さん
02002:緒方さん
|