這次帶給大家PHP狀態模式使用詳解,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中文网其它相关文章!
推荐阅读:
以上是PHP狀態模式使用詳解的詳細內容。更多資訊請關注PHP中文網其他相關文章!