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



last updated
2002/03/17

counter hits
since 1999/11/06


PHP4でデザインパターン(Visitor編)

zip形式 tgz形式

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

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

今回は、Visitorパターンで「データ構造と処理を分離する」パターンです(以下のクラス図を参照)。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_;

        :

    /**
     * Entryを取り出すためのiteratorオブジェクトを返す
     */
    function iterator()
    {
        return new Iterator($this->entry_);
    }

    /**
     * 「訪問者」を受け入れるときの具体的な処理
     * visitメソッドをコールする
     */
    function accept($visitor)
    {
        $visitor->visit($this);
    }
}

class Emp extends Entry
{
        :

    /**
     * 「訪問者」を受け入れるときの具体的な処理
     * visitメソッドをコールする
     */
    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);
            }
        }
    }
}

/**
 * 「[PHP-users 6001] PHPデザインパタン」で黒木さんが示されたIteratorを
 * 使用させていただきましたm(_"_)m
 */
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:緒方さん
  


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