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



last updated
2005/05/25

counter hits
since 1999/11/06


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

zip形式 tgz形式

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

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

今回は、Stateパターンで、「状態をクラスで表す」パターンです(以下のクラス図を参照)。

Stateパターンのクラス図

今回のサンプルは、ユーザーの認証状態(未認証・認証後)をそれぞれ表すクラスを作成し、ユーザー名と利用可能なメニューを返すメソッドを用意しました。それぞれのクラスには、Singletonパターンも含まれています。

普通に考えると、1つのクラスのみを作成してメソッド内で認証されているかどうかを判断するif文を使うことになりますが、Stateパターンを使うとその必要がありません。

ということで、以下がサンプルコードです。また、Abstractクラスなどを含めたスクリプトコードは、上のリンクからダウンロードできます。なお、PHP4.1.x用ですが、セッション変数($_SESSION)を書き換えれば、4.0.6でも動作すると思います。。。あ、register_globalsはOffですので、ご注意を。。。

●State.php

<?php
require_once("jp/ne/hi_ho/pat/dimension/Abstract.phl");
?>
<?php
/**
 * 状態毎の動作・振る舞いを定義する。interface的な位置づけ。
 */
class UserState
{
    function &getInstance() { Abstract::set("getInstance"); }
    function state($context) { Abstract::set("state"); }
    function getUserName() { Abstract::set("getUserName"); }
    function getMenuUrl() { Abstract::set("getMenuUrl"); }
}

/**
 * 認証後の状態を表すクラス
 */
class AuthorizedState extends UserState
{
    function &getInstance()
    {
        static $singleton;
        if ($singleton == null) {
            $singleton = new AuthorizedState();
        }
        return $singleton;
    }
    function nextState()
    {
        // 次の状態(未認証)を返す
        return UnauthorizedState::getInstance();
    }
    function getUserName()
    {
        return "メンバー";
    }
    function getMenuUrl()
    {
        $url = basename(__FILE__);
        $menu = "<a href=\"" . $url . "?mode=inc\">カウントアップ</a> | "
              . "<a href=\"" . $url . "?mode=reset\">リセット</a> | "
              . "<a href=\"" . $url . "?mode=state\">ログアウト</a>";
        return $menu;
    }
}

/**
 * 未認証の状態を表すクラス
 */
class UnauthorizedState extends UserState
{
    function &getInstance()
    {
        static $singleton;
        if ($singleton == null) {
            $singleton = new UnauthorizedState();
        }
        return $singleton;
    }
    function nextState()
    {
        // 次の状態(認証)を返す
        return AuthorizedState::getInstance();
    }
    function getUserName()
    {
        return "通りすがり@お腹いっぱい";
    }
    function getMenuUrl()
    {
        $url = basename(__FILE__);
        $menu = "<a href=\"" . $url  . "?mode=state\">ログイン</a>";
        return $menu;
    }
}

/**
 * 現在の状態を表すクラス
 */
class Context
{
    var $state_;
    var $count_;
    function Context()
    {
        // 初期値
        $this->state_ = UnauthorizedState::getInstance();
        $this->resetCount();
    }
    function changeState()
    {
        echo "状態遷移:" . get_class($this->state_) . "→";
        $this->state_ = $this->state_->nextState();
        echo get_class($this->state_) . "<br>";
        $this->resetCount();
    }
    function getUserName()
    {
        return $this->state_->getUserName();
    }
    function getMenu()
    {
        return $this->state_->getMenuUrl();
    }
    function getCount()
    {
        return $this->count_;
    }
    function incrementCount()
    {
        $this->count_++;
    }
    function resetCount()
    {
        $this->count_ = 0;
    }
}
?>
<?php
    /**
     * main
     */
    $SESSION_KEY_NAME = "state";
    session_start();
    if (!isset($_SESSION[$SESSION_KEY_NAME])) {
        $_SESSION[$SESSION_KEY_NAME] = new Context();
    }
    $context = $_SESSION[$SESSION_KEY_NAME];
    if (isset($_GET["mode"]) && $_GET["mode"] == "state") {
        echo "状態を遷移します<br>";
        $context->changeState();
    }
    else if (isset($_GET["mode"]) && $_GET["mode"] == "inc") {
        echo "カウントアップします<br>";
        $context->incrementCount();
    }
    else if (isset($_GET["mode"]) && $_GET["mode"] == "reset") {
        echo "カウントをリセットします<br>";
        $context->resetCount();
    }
    $_SESSION[$SESSION_KEY_NAME] = $context;

    echo "ようこそ、" . $context->getUserName() . "さん<br>";
    echo "カウント:" . $context->getCount() . "<br>";
    echo $context->getMenu() . "<br>";
?>

●出力結果(ログイン後)
状態を遷移します
状態遷移:unauthorizedstate→authorizedstate
ようこそ、メンバーさん
カウント:0
カウントアップ | リセット | ログアウト
●出力結果(ログアウト後)
状態を遷移します
状態遷移:authorizedstate→unauthorizedstate
ようこそ、通りすがり@お腹いっぱいさん
カウント:0
ログイン


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