|
zip形式
tgz形式
オブジェクト指向についてはまだまだ勉強中ですが、「PHPでGoFのデザインパターンを実装したら、どんな感じになるんだろ?」と思ってしまったので、ちょっとずつやってみることにしました。
間違いやご意見がありましたら、遠慮なくツッコミを入れてくださいm(_"_)m
今回は、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
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
$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
ログイン
|