本文實例講述了PHP設計模式之狀態模式定義與用法。分享給大家供大家參考,具體如下:
什么是狀態設計模式
當一個對象的內在狀態改變時允許改變其行為,這個對象看起來像是改變了其類。
狀態模式主要解決的是當控制一個對象狀態的條件表達式過于復雜時的情況。把狀態的判斷邏輯轉移到表示不同狀態的一系列類中,可以把復雜的判斷邏輯簡化。
什么時候使用狀態模式
對象中頻繁改變非常依賴于條件語句。 就其自身來說, 條件語句本身沒有什么問題(如switch語句或帶else子句的語句),不過, 如果選項太多, 以到程序開始出現混亂, 或者增加或改變選項需要花費太多時間, 甚至成為一種負擔, 這就出現了問題
對于狀態設計模式, 每個狀態都有自己的具體類, 它們實現一個公共接口. 我們不用查看對象的控制流, 而是從另一個角度來考慮, 即對象的狀態.
狀態機是一個模型, 其重點包括不同的狀態, 一個狀態到另一個狀態的變遷, 以及導致狀態改變的觸發器.
以開燈關燈為例子, 狀態模型的本質分為3點:
①狀態(關燈和開燈)
②變遷(從關燈到開燈, 以及從開燈到關燈)
③觸發器(燈開關)
所以狀態模式都需要一個參與者來跟蹤對象所處的狀態. 以Light為例, Light需要知道當前狀態是什么.
示例:開燈關燈
Light.php
<?php class Light { private $offState; //關閉狀態 private $onState; //開啟狀態 private $currentState; //當前狀態 public function __construct() { $this->offState = new OffState($this); $this->onState = new OnState($this); //開始狀態為關閉狀態Off $this->currentState = $this->offState; } //調用狀態方法觸發器 public function turnLightOn() { $this->currentState->turnLightOn(); } public function turnLightOff() { $this->currentState->turnLightOff(); } //設置當前狀態 public function setState(IState $state) { $this->currentState = $state; } //獲取狀態 public function getOnState() { return $this->onState; } public function getOffState() { return $this->offState; } }
在構造函數中, Light實例化IState實現的兩個實例-----一個對應關, 一個對應開
$this->offState = new OffState($this); $this->onState = new OnState($this);
這個實例化過程用到了一種遞歸, 稱為自引用(self-referral)
構造函數參數中的實參寫為$this, 這是Light類自身的一個引用. 狀態類希望接收一個Light類實例做參數,.
setState方法是為了設置一個當前狀態 需要一個狀態對象作為實參, 一旦觸發一個狀態, 這個狀態就會向Light類發送信息, 指定當前狀態.
狀態實例
IState接口
IState.php
<?php interface IState { public function turnLightOn(); public function turnLightOff(); }
該接口的實現類
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 "燈關閉!看不見帥哥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 "燈已經關閉了->不做操作<br />"; } }
默認狀態是OffState, 它必須實現IState方法turnLightOn和turnLightOff, Light調用turnLightOn方法, 會顯示(燈打開!可以看見帥哥chenqionghe了), 然后將OnState設置為當前狀態, 不過,如果是調用 OffState的turnLightOff方法, 就只有提示燈已經被關閉了 不會有其他動作.
客戶
Client的所有請求都是通過Light發出, Client和任何狀態類之間都沒有直接連接, 包括IState接口.下面的Client顯示了觸發兩個狀態中所有方法的請求.
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();
增加狀態
對于所有的設計模式來說,很重要的一個方面是: 利用這些設計模式可以很容易地做出修改. 與其他模式一樣,狀態模式也很易于更新和改變. 下面在這個燈的示例上再加兩個狀態:更亮(Brighter)和最亮(Brightest)
現在變成了4個狀態, 序列有所改變. '關'(off)狀態只能變到"開"(on)狀態, on狀態不能變到off狀態. on狀態只能變到"更亮"(brighter)狀態和"最亮"(brightest)狀態. 只能最亮狀態才可能變到關狀態.
改變接口
要改變的第一個參與者是接口IState, 這個接口中必須指定相應的方法, 可以用來遷移到brighter和brightest狀態.
IState.php
<?php interface IState { public function turnLightOn(); public function turnLightOff(); public function turnBrighter(); public function turnBrightest(); }
現在所有狀態類都必須包含這4個方法, 它們都需要結合到Light類中.
改變狀態
狀態設計模式中有改變時, 這些新增的改變會對模式整體的其他方面帶來影響. 不過, 增加改變相當簡單, 每個狀態只有一個特定的變遷.
四個狀態
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 "燈關閉!看不見帥哥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已經帥到無敵!<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 "燈已經打開了->不做操作<br />"; } public function turnLightOff() { echo "燈關閉!看不見帥哥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; //關閉狀態 private $onState; //開啟狀態 private $brighterState; //更亮狀態 private $brightestState;//最亮狀態 private $currentState; //當前狀態 public function __construct() { $this->offState = new OffState($this); $this->onState = new OnState($this); $this->brighterState = new BrighterState($this); $this->brightestState = new BrightestState($this); //開始狀態為關閉狀態Off $this->currentState = $this->offState; } //調用狀態方法觸發器 public function turnLightOn() { $this->currentState->turnLightOn(); } public function turnLightOff() { $this->currentState->turnLightOff(); } public function turnLightBrighter() { $this->currentState->turnBrighter(); } public function turnLigthBrightest() { $this->currentState->turnBrightest(); } //設置當前狀態 public function setState(IState $state) { $this->currentState = $state; } //獲取狀態 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();
運行結果如下
燈打開!可以看見帥哥chenqionghe了!
燈更亮了, 看帥哥chenqionghe看得更真切了!
燈最亮了, 看帥哥chenqionghe已經帥到無敵!
燈關閉!看不見帥哥chenqionghe了!
不合法的操作!
九宮格移動示例
九宮格的移動分為4個移動:
上(Up)
下(Down)
左(Left)
右(Right)
對于這些移動,規則是要求單元格之間不能沿對角線方向移動. 另外, 從一個單元格移動到下一個單元格時, 一次只能移動一個單元格
要使用狀態設計模式來建立一個九宮格移動示例,
建立接口
IMatrix.php
<?php interface IMatrix { public function goUp(); public function goDown(); public function goLeft(); public function goRight(); }
雖然這個狀態設計模式有9個狀態, 分別對應九個單元格, 但一個狀態最多只需要4個變遷
上下文
對于狀態中的4個變遷或移動方法, 上下文必須提供相應方法來調用這些變遷方法, 另外還要完成各個狀態的實例化.
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; } //調用方法 public function doUp() { $this->currentState->goUp(); } public function doDown() { $this->currentState->goDown(); } public function doLeft() { $this->currentState->goLeft(); } public function doRight() { $this->currentState->goRight(); } //設置當前狀態 public function setState(IMatrix $state) { $this->currentState = $state; } //獲取狀態 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; } }
狀態
9個狀態表示九宮格中的不同單元格, 為了唯一顯示單元格,會分別輸出相應到達的單元格數字, 這樣能夠更清楚地看出穿過矩陣的路線.
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 />'; } }
要想有效地使用狀態設計模式, 真正的難點在于要想象現實或模擬世界是怎么樣
客戶Client
下面從單元格5開始進行一個上,右,下, 下,左,上的移動
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();
運行結果如下
走到2
走到3
走到6
走到9
走到8
走到5
狀態模式與PHP
很多人把狀態設計模式看做是實現模擬器和游戲的主要方法.總的說來, 這確實是狀態模式的目標,不過險些之外, 狀態模型(狀態引擎)和狀態設計模式在PHP中也有很多應用.用PHP完成更大的項目時, 包括Facebook和WordPress, 會有更多的新增特性和當前狀態需求.對于這種不斷有改變和增長的情況, 就可以采用可擴展的狀態模式來管理.
PHP開發人員如何創建包含多個狀態的程序, 將決定狀態模式的使用范圍. 所以不僅狀態機在游戲和模擬世界中有很多應用, 實際上狀態模型還有更多適用的領域.只要PHP程序的用戶會用到一組有限的狀態, 開發人員就可以使用狀態設計模式.
希望本文所述對大家PHP程序設計有所幫助。