本文實(shí)例講述了PHP設(shè)計模式之狀態(tài)模式定義與用法。分享給大家供大家參考,具體如下:
什么是狀態(tài)設(shè)計模式
當(dāng)一個對象的內(nèi)在狀態(tài)改變時允許改變其行為,這個對象看起來像是改變了其類。
狀態(tài)模式主要解決的是當(dāng)控制一個對象狀態(tài)的條件表達(dá)式過于復(fù)雜時的情況。把狀態(tài)的判斷邏輯轉(zhuǎn)移到表示不同狀態(tài)的一系列類中,可以把復(fù)雜的判斷邏輯簡化。
什么時候使用狀態(tài)模式
對象中頻繁改變非常依賴于條件語句。 就其自身來說, 條件語句本身沒有什么問題(如switch語句或帶else子句的語句),不過, 如果選項(xiàng)太多, 以到程序開始出現(xiàn)混亂, 或者增加或改變選項(xiàng)需要花費(fèi)太多時間, 甚至成為一種負(fù)擔(dān), 這就出現(xiàn)了問題
對于狀態(tài)設(shè)計模式, 每個狀態(tài)都有自己的具體類, 它們實(shí)現(xiàn)一個公共接口. 我們不用查看對象的控制流, 而是從另一個角度來考慮, 即對象的狀態(tài).
狀態(tài)機(jī)是一個模型, 其重點(diǎn)包括不同的狀態(tài), 一個狀態(tài)到另一個狀態(tài)的變遷, 以及導(dǎo)致狀態(tài)改變的觸發(fā)器.
以開燈關(guān)燈為例子, 狀態(tài)模型的本質(zhì)分為3點(diǎn):
①狀態(tài)(關(guān)燈和開燈)
②變遷(從關(guān)燈到開燈, 以及從開燈到關(guān)燈)
③觸發(fā)器(燈開關(guān))
所以狀態(tài)模式都需要一個參與者來跟蹤對象所處的狀態(tài). 以Light為例, Light需要知道當(dāng)前狀態(tài)是什么.
示例:開燈關(guān)燈
Light.php
?php
class Light
{
private $offState; //關(guān)閉狀態(tài)
private $onState; //開啟狀態(tài)
private $currentState; //當(dāng)前狀態(tài)
public function __construct()
{
$this->offState = new OffState($this);
$this->onState = new OnState($this);
//開始狀態(tài)為關(guān)閉狀態(tài)Off
$this->currentState = $this->offState;
}
//調(diào)用狀態(tài)方法觸發(fā)器
public function turnLightOn()
{
$this->currentState->turnLightOn();
}
public function turnLightOff()
{
$this->currentState->turnLightOff();
}
//設(shè)置當(dāng)前狀態(tài)
public function setState(IState $state)
{
$this->currentState = $state;
}
//獲取狀態(tài)
public function getOnState()
{
return $this->onState;
}
public function getOffState()
{
return $this->offState;
}
}
在構(gòu)造函數(shù)中, Light實(shí)例化IState實(shí)現(xiàn)的兩個實(shí)例-----一個對應(yīng)關(guān), 一個對應(yīng)開
$this->offState = new OffState($this);
$this->onState = new OnState($this);
這個實(shí)例化過程用到了一種遞歸, 稱為自引用(self-referral)
構(gòu)造函數(shù)參數(shù)中的實(shí)參寫為$this, 這是Light類自身的一個引用. 狀態(tài)類希望接收一個Light類實(shí)例做參數(shù),.
setState方法是為了設(shè)置一個當(dāng)前狀態(tài) 需要一個狀態(tài)對象作為實(shí)參, 一旦觸發(fā)一個狀態(tài), 這個狀態(tài)就會向Light類發(fā)送信息, 指定當(dāng)前狀態(tài).
狀態(tài)實(shí)例
IState接口
IState.php
?php
interface IState
{
public function turnLightOn();
public function turnLightOff();
}
該接口的實(shí)現(xiàn)類
OnState.php
?php
class OnState implements IState
{
private $light;
public function __construct(Light $light)
{
$this->light = $light;
}
public function turnLightOn()
{
echo "燈已經(jīng)打開了->不做操作br />";
}
public function turnLightOff()
{
echo "燈關(guān)閉!看不見帥哥chenqionghe了!br />";
$this->light->setState($this->light->getOffState());
}
}
OffState.php
?php
class OffState implements IState
{
private $light;
public function __construct(Light $light)
{
$this->light = $light;
}
public function turnLightOn()
{
echo "燈打開!可以看見帥哥chenqionghe了!br />";
$this->light->setState($this->light->getOnState());
}
public function turnLightOff()
{
echo "燈已經(jīng)關(guān)閉了->不做操作br />";
}
}
默認(rèn)狀態(tài)是OffState, 它必須實(shí)現(xiàn)IState方法turnLightOn和turnLightOff, Light調(diào)用turnLightOn方法, 會顯示(燈打開!可以看見帥哥chenqionghe了), 然后將OnState設(shè)置為當(dāng)前狀態(tài), 不過,如果是調(diào)用 OffState的turnLightOff方法, 就只有提示燈已經(jīng)被關(guān)閉了 不會有其他動作.
客戶
Client的所有請求都是通過Light發(fā)出, Client和任何狀態(tài)類之間都沒有直接連接, 包括IState接口.下面的Client顯示了觸發(fā)兩個狀態(tài)中所有方法的請求.
Client.php
?php
function __autoload($class_name)
{
include_once $class_name.'.php';
}
class Client
{
private $light;
public function __construct()
{
$this->light = new Light();
$this->light->turnLightOn();
$this->light->turnLightOn();
$this->light->turnLightOff();
$this->light->turnLightOff();
}
}
$worker = new Client();
增加狀態(tài)
對于所有的設(shè)計模式來說,很重要的一個方面是: 利用這些設(shè)計模式可以很容易地做出修改. 與其他模式一樣,狀態(tài)模式也很易于更新和改變. 下面在這個燈的示例上再加兩個狀態(tài):更亮(Brighter)和最亮(Brightest)
現(xiàn)在變成了4個狀態(tài), 序列有所改變. '關(guān)'(off)狀態(tài)只能變到"開"(on)狀態(tài), on狀態(tài)不能變到off狀態(tài). on狀態(tài)只能變到"更亮"(brighter)狀態(tài)和"最亮"(brightest)狀態(tài). 只能最亮狀態(tài)才可能變到關(guān)狀態(tài).
改變接口
要改變的第一個參與者是接口IState, 這個接口中必須指定相應(yīng)的方法, 可以用來遷移到brighter和brightest狀態(tài).
IState.php
?php
interface IState
{
public function turnLightOn();
public function turnLightOff();
public function turnBrighter();
public function turnBrightest();
}
現(xiàn)在所有狀態(tài)類都必須包含這4個方法, 它們都需要結(jié)合到Light類中.
改變狀態(tài)
狀態(tài)設(shè)計模式中有改變時, 這些新增的改變會對模式整體的其他方面帶來影響. 不過, 增加改變相當(dāng)簡單, 每個狀態(tài)只有一個特定的變遷.
四個狀態(tài)
OnState.php
?php
class OnState implements IState
{
private $light;
public function __construct(Light $light)
{
$this->light = $light;
}
public function turnLightOn()
{
echo "不合法的操作!br />";
}
public function turnLightOff()
{
echo "燈關(guān)閉!看不見帥哥chenqionghe了!br />";
$this->light->setState($this->light->getOffState());
}
public function turnBrighter()
{
echo "燈更亮了, 看帥哥chenqionghe看得更真切了!br />";
$this->light->setState($this->light->getBrighterState());
}
public function turnBrightest()
{
echo "不合法的操作!br />";
}
}
OffState.php
?php
class OffState implements IState
{
private $light;
public function __construct(Light $light)
{
$this->light = $light;
}
public function turnLightOn()
{
echo "燈打開!可以看見帥哥chenqionghe了!br />";
$this->light->setState($this->light->getOnState());
}
public function turnLightOff()
{
echo "不合法的操作!br />";
}
public function turnBrighter()
{
echo "不合法的操作!br />";
}
public function turnBrightest()
{
echo "不合法的操作!br />";
}
}
Brighter.php
?php
class BrighterState implements IState
{
private $light;
public function __construct(Light $light)
{
$this->light = $light;
}
public function turnLightOn()
{
echo "不合法的操作!br />";
}
public function turnLightOff()
{
echo "不合法的操作!br />";
}
public function turnBrighter()
{
echo "不合法的操作!br />";
}
public function turnBrightest()
{
echo "燈最亮了, 看帥哥chenqionghe已經(jīng)帥到無敵!br />";
$this->light->setState($this->light->getBrightestState());
}
}
Brightest.php
?php
class BrightestState implements IState
{
private $light;
public function __construct(Light $light)
{
$this->light = $light;
}
public function turnLightOn()
{
echo "燈已經(jīng)打開了->不做操作br />";
}
public function turnLightOff()
{
echo "燈關(guān)閉!看不見帥哥chenqionghe了!br />";
$this->light->setState($this->light->getOffState());
}
public function turnBrighter()
{
echo "不合法的操作!br />";
}
public function turnBrightest()
{
echo "不合法的操作!br />";
}
}
更新Light類
Light.php
?php
class Light
{
private $offState; //關(guān)閉狀態(tài)
private $onState; //開啟狀態(tài)
private $brighterState; //更亮狀態(tài)
private $brightestState;//最亮狀態(tài)
private $currentState; //當(dāng)前狀態(tài)
public function __construct()
{
$this->offState = new OffState($this);
$this->onState = new OnState($this);
$this->brighterState = new BrighterState($this);
$this->brightestState = new BrightestState($this);
//開始狀態(tài)為關(guān)閉狀態(tài)Off
$this->currentState = $this->offState;
}
//調(diào)用狀態(tài)方法觸發(fā)器
public function turnLightOn()
{
$this->currentState->turnLightOn();
}
public function turnLightOff()
{
$this->currentState->turnLightOff();
}
public function turnLightBrighter()
{
$this->currentState->turnBrighter();
}
public function turnLigthBrightest()
{
$this->currentState->turnBrightest();
}
//設(shè)置當(dāng)前狀態(tài)
public function setState(IState $state)
{
$this->currentState = $state;
}
//獲取狀態(tài)
public function getOnState()
{
return $this->onState;
}
public function getOffState()
{
return $this->offState;
}
public function getBrighterState()
{
return $this->brighterState;
}
public function getBrightestState()
{
return $this->brightestState;
}
}
更新客戶
?php
function __autoload($class_name)
{
include_once $class_name.'.php';
}
class Client
{
private $light;
public function __construct()
{
$this->light = new Light();
$this->light->turnLightOn();
$this->light->turnLightBrighter();
$this->light->turnLigthBrightest();
$this->light->turnLightOff();
$this->light->turnLigthBrightest();
}
}
$worker = new Client();
運(yùn)行結(jié)果如下
燈打開!可以看見帥哥chenqionghe了!
燈更亮了, 看帥哥chenqionghe看得更真切了!
燈最亮了, 看帥哥chenqionghe已經(jīng)帥到無敵!
燈關(guān)閉!看不見帥哥chenqionghe了!
不合法的操作!
九宮格移動示例
九宮格的移動分為4個移動:
上(Up)
下(Down)
左(Left)
右(Right)
對于這些移動,規(guī)則是要求單元格之間不能沿對角線方向移動. 另外, 從一個單元格移動到下一個單元格時, 一次只能移動一個單元格
要使用狀態(tài)設(shè)計模式來建立一個九宮格移動示例,
建立接口
IMatrix.php
?php
interface IMatrix
{
public function goUp();
public function goDown();
public function goLeft();
public function goRight();
}
雖然這個狀態(tài)設(shè)計模式有9個狀態(tài), 分別對應(yīng)九個單元格, 但一個狀態(tài)最多只需要4個變遷
上下文
對于狀態(tài)中的4個變遷或移動方法, 上下文必須提供相應(yīng)方法來調(diào)用這些變遷方法, 另外還要完成各個狀態(tài)的實(shí)例化.
Context.php
?php
class Context
{
private $cell1;
private $cell2;
private $cell3;
private $cell4;
private $cell5;
private $cell6;
private $cell7;
private $cell8;
private $cell9;
private $currentState;
public function __construct()
{
$this->cell1 = new Cell1State($this);
$this->cell2 = new Cell2State($this);
$this->cell3 = new Cell3State($this);
$this->cell4 = new Cell4State($this);
$this->cell5 = new Cell5State($this);
$this->cell6 = new Cell6State($this);
$this->cell7 = new Cell7State($this);
$this->cell8 = new Cell8State($this);
$this->cell9 = new Cell9State($this);
$this->currentState = $this->cell5;
}
//調(diào)用方法
public function doUp()
{
$this->currentState->goUp();
}
public function doDown()
{
$this->currentState->goDown();
}
public function doLeft()
{
$this->currentState->goLeft();
}
public function doRight()
{
$this->currentState->goRight();
}
//設(shè)置當(dāng)前狀態(tài)
public function setState(IMatrix $state)
{
$this->currentState = $state;
}
//獲取狀態(tài)
public function getCell1State()
{
return $this->cell1;
}
public function getCell2State()
{
return $this->cell2;
}
public function getCell3State()
{
return $this->cell3;
}
public function getCell4State()
{
return $this->cell4;
}
public function getCell5State()
{
return $this->cell5;
}
public function getCell6State()
{
return $this->cell6;
}
public function getCell7State()
{
return $this->cell7;
}
public function getCell8State()
{
return $this->cell8;
}
public function getCell9State()
{
return $this->cell9;
}
}
狀態(tài)
9個狀態(tài)表示九宮格中的不同單元格, 為了唯一顯示單元格,會分別輸出相應(yīng)到達(dá)的單元格數(shù)字, 這樣能夠更清楚地看出穿過矩陣的路線.
Cell1State
?php
class Cell1State implements IMatrix
{
private $context;
public function __construct(Context $contextNow)
{
$this->context = $contextNow;
}
public function goLeft()
{
echo '不合法的移動!br />';
}
public function goRight()
{
echo '走到strong>2/strong>br />';
$this->context->setState($this->context->getCell2State());
}
public function goUp()
{
echo '不合法的移動!br />';
}
public function goDown()
{
echo '走到strong>4/strong>br />';
$this->context->setState($this->context->getCell4State());
}
}
Cell2State
?php
class Cell2State implements IMatrix
{
private $context;
public function __construct(Context $contextNow)
{
$this->context = $contextNow;
}
public function goLeft()
{
echo '走到strong>1/strong>br />';
$this->context->setState($this->context->getCell1State());
}
public function goRight()
{
echo '走到strong>3/strong>br />';
$this->context->setState($this->context->getCell3State());
}
public function goUp()
{
echo '不合法的移動!br />';
}
public function goDown()
{
echo '走到strong>5/strong>br />';
$this->context->setState($this->context->getCell5State());
}
}
Cell3State
?php
class Cell3State implements IMatrix
{
private $context;
public function __construct(Context $contextNow)
{
$this->context = $contextNow;
}
public function goLeft()
{
echo '走到strong>2/strong>br />';
$this->context->setState($this->context->getCell2State());
}
public function goRight()
{
echo '不合法的移動!br />';
}
public function goUp()
{
echo '不合法的移動!br />';
}
public function goDown()
{
echo '走到strong>6/strong>br />';
$this->context->setState($this->context->getCell6State());
}
}
Cell4State
?php
class Cell4State implements IMatrix
{
private $context;
public function __construct(Context $contextNow)
{
$this->context = $contextNow;
}
public function goLeft()
{
echo '不合法的移動!br />';
}
public function goRight()
{
echo '走到strong>5/strong>br />';
$this->context->setState($this->context->getCell5State());
}
public function goUp()
{
echo '走到strong>1/strong>br />';
$this->context->setState($this->context->getCell1State());
}
public function goDown()
{
echo '走到strong>7/strong>br />';
$this->context->setState($this->context->getCell7State());
}
}
Cell5State
?php
class Cell5State implements IMatrix
{
private $context;
public function __construct(Context $contextNow)
{
$this->context = $contextNow;
}
public function goLeft()
{
echo '走到strong>4/strong>br />';
$this->context->setState($this->context->getCell4State());
}
public function goRight()
{
echo '走到strong>6/strong>br />';
$this->context->setState($this->context->getCell6State());
}
public function goUp()
{
echo '走到strong>2/strong>br />';
$this->context->setState($this->context->getCell2State());
}
public function goDown()
{
echo '走到strong>8/strong>br />';
$this->context->setState($this->context->getCell8State());
}
}
Cell6State
?php
class Cell6State implements IMatrix
{
private $context;
public function __construct(Context $contextNow)
{
$this->context = $contextNow;
}
public function goLeft()
{
echo '走到strong>5/strong>br />';
$this->context->setState($this->context->getCell5State());
}
public function goRight()
{
echo '不合法的移動!br />';
}
public function goUp()
{
echo '走到strong>3/strong>br />';
$this->context->setState($this->context->getCell3State());
}
public function goDown()
{
echo '走到strong>9/strong>br />';
$this->context->setState($this->context->getCell9State());
}
}
Cell7State
?php
class Cell7State implements IMatrix
{
private $context;
public function __construct(Context $contextNow)
{
$this->context = $contextNow;
}
public function goLeft()
{
echo '不合法的移動!br />';
}
public function goRight()
{
echo '走到strong>8/strong>br />';
$this->context->setState($this->context->getCell8State());
}
public function goUp()
{
echo '走到strong>4/strong>br />';
$this->context->setState($this->context->getCell4State());
}
public function goDown()
{
echo '不合法的移動!br />';
}
}
Cell8State
?php
class Cell8State implements IMatrix
{
private $context;
public function __construct(Context $contextNow)
{
$this->context = $contextNow;
}
public function goLeft()
{
echo '走到strong>7/strong>br />';
$this->context->setState($this->context->getCell7State());
}
public function goRight()
{
echo '走到strong>9/strong>br />';
$this->context->setState($this->context->getCell9State());
}
public function goUp()
{
echo '走到strong>5/strong>br />';
$this->context->setState($this->context->getCell5State());
}
public function goDown()
{
echo '不合法的移動!br />';
}
}
Cell9State
?php
class Cell9State implements IMatrix
{
private $context;
public function __construct(Context $contextNow)
{
$this->context = $contextNow;
}
public function goLeft()
{
echo '走到strong>8/strong>br />';
$this->context->setState($this->context->getCell8State());
}
public function goRight()
{
echo '不合法的移動!br />';
}
public function goUp()
{
echo '走到strong>6/strong>br />';
$this->context->setState($this->context->getCell6State());
}
public function goDown()
{
echo '不合法的移動!br />';
}
}
要想有效地使用狀態(tài)設(shè)計模式, 真正的難點(diǎn)在于要想象現(xiàn)實(shí)或模擬世界是怎么樣
客戶Client
下面從單元格5開始進(jìn)行一個上,右,下, 下,左,上的移動
Client.php
?php
function __autoload($class_name)
{
include_once $class_name.'.php';
}
class Client
{
private $context;
public function __construct()
{
$this->context = new Context();
$this->context->doUp();
$this->context->doRight();
$this->context->doDown();
$this->context->doDown();
$this->context->doLeft();
$this->context->doUp();
}
}
$worker = new Client();
運(yùn)行結(jié)果如下
走到2
走到3
走到6
走到9
走到8
走到5
狀態(tài)模式與PHP
很多人把狀態(tài)設(shè)計模式看做是實(shí)現(xiàn)模擬器和游戲的主要方法.總的說來, 這確實(shí)是狀態(tài)模式的目標(biāo),不過險些之外, 狀態(tài)模型(狀態(tài)引擎)和狀態(tài)設(shè)計模式在PHP中也有很多應(yīng)用.用PHP完成更大的項(xiàng)目時, 包括Facebook和WordPress, 會有更多的新增特性和當(dāng)前狀態(tài)需求.對于這種不斷有改變和增長的情況, 就可以采用可擴(kuò)展的狀態(tài)模式來管理.
PHP開發(fā)人員如何創(chuàng)建包含多個狀態(tài)的程序, 將決定狀態(tài)模式的使用范圍. 所以不僅狀態(tài)機(jī)在游戲和模擬世界中有很多應(yīng)用, 實(shí)際上狀態(tài)模型還有更多適用的領(lǐng)域.只要PHP程序的用戶會用到一組有限的狀態(tài), 開發(fā)人員就可以使用狀態(tài)設(shè)計模式.
更多關(guān)于PHP相關(guān)內(nèi)容感興趣的讀者可查看本站專題:《php面向?qū)ο蟪绦蛟O(shè)計入門教程》、《PHP基本語法入門教程》、《PHP數(shù)組(Array)操作技巧大全》、《php字符串(string)用法總結(jié)》、《php+mysql數(shù)據(jù)庫操作入門教程》及《php常見數(shù)據(jù)庫操作技巧匯總》
希望本文所述對大家PHP程序設(shè)計有所幫助。
您可能感興趣的文章:- php設(shè)計模式 State (狀態(tài)模式)
- 學(xué)習(xí)php設(shè)計模式 php實(shí)現(xiàn)狀態(tài)模式
- php設(shè)計模式之狀態(tài)模式實(shí)例分析【星際爭霸游戲案例】
- PHP設(shè)計模式之觀察者模式(Observer)詳細(xì)介紹和代碼實(shí)例
- PHP常用的三種設(shè)計模式匯總
- PHP經(jīng)典面試題之設(shè)計模式(經(jīng)常遇到)
- php設(shè)計模式小結(jié)
- php 設(shè)計模式之 工廠模式
- php基礎(chǔ)設(shè)計模式大全(注冊樹模式、工廠模式、單列模式)
- PHP設(shè)計模式入門之狀態(tài)模式原理與實(shí)現(xiàn)方法分析