PHP设计模式之状态模式定义与用法详解
本文实例讲述了PHP设计模式之状态模式定义与用法。分享给大家供大家参考,具体如下:
什么是状态设计模式
当一个对象的内在状态改变时允许改变其行为,这个对象看起来像是改变了其类。
状态模式主要解决的是当控制一个对象状态的条件表达式过于复杂时的情况。把状态的判断逻辑转移到表示不同状态的一系列类中,可以把复杂的判断逻辑简化。
什么时候使用状态模式
对象中频繁改变非常依赖于条件语句。就其自身来说,条件语句本身没有什么问题(如switch语句或带else子句的语句),不过,如果选项太多,以到程序开始出现混乱,或者增加或改变选项需要花费太多时间,甚至成为一种负担,这就出现了问题
对于状态设计模式,每个状态都有自己的具体类,它们实现一个公共接口.我们不用查看对象的控制流,而是从另一个角度来考虑,即对象的状态.
状态机是一个模型,其重点包括不同的状态,一个状态到另一个状态的变迁,以及导致状态改变的触发器.
以开灯关灯为例子,状态模型的本质分为3点:
①状态(关灯和开灯)
②变迁(从关灯到开灯,以及从开灯到关灯)
③触发器(灯开关)
所以状态模式都需要一个参与者来跟踪对象所处的状态.以Light为例,Light需要知道当前状态是什么.
示例:开灯关灯
Light.php
offState=newOffState($this); $this->onState=newOnState($this); //开始状态为关闭状态Off $this->currentState=$this->offState; } //调用状态方法触发器 publicfunctionturnLightOn() { $this->currentState->turnLightOn(); } publicfunctionturnLightOff() { $this->currentState->turnLightOff(); } //设置当前状态 publicfunctionsetState(IState$state) { $this->currentState=$state; } //获取状态 publicfunctiongetOnState() { return$this->onState; } publicfunctiongetOffState() { return$this->offState; } }
在构造函数中,Light实例化IState实现的两个实例-----一个对应关,一个对应开
$this->offState=newOffState($this); $this->onState=newOnState($this);
这个实例化过程用到了一种递归,称为自引用(self-referral)
构造函数参数中的实参写为$this,这是Light类自身的一个引用.状态类希望接收一个Light类实例做参数,.
setState方法是为了设置一个当前状态需要一个状态对象作为实参,一旦触发一个状态,这个状态就会向Light类发送信息,指定当前状态.
状态实例
IState接口
IState.php
该接口的实现类
OnState.php
light=$light; } publicfunctionturnLightOn() { echo"灯已经打开了->不做操作
"; } publicfunctionturnLightOff() { echo"灯关闭!看不见帅哥chenqionghe了!
"; $this->light->setState($this->light->getOffState()); } }OffState.php
light=$light; } publicfunctionturnLightOn() { echo"灯打开!可以看见帅哥chenqionghe了!
"; $this->light->setState($this->light->getOnState()); } publicfunctionturnLightOff() { echo"灯已经关闭了->不做操作
"; } }默认状态是OffState,它必须实现IState方法turnLightOn和turnLightOff,Light调用turnLightOn方法,会显示(灯打开!可以看见帅哥chenqionghe了),然后将OnState设置为当前状态,不过,如果是调用OffState的turnLightOff方法,就只有提示灯已经被关闭了不会有其他动作.
客户
Client的所有请求都是通过Light发出,Client和任何状态类之间都没有直接连接,包括IState接口.下面的Client显示了触发两个状态中所有方法的请求.
Client.php
light=newLight(); $this->light->turnLightOn(); $this->light->turnLightOn(); $this->light->turnLightOff(); $this->light->turnLightOff(); } } $worker=newClient();增加状态
对于所有的设计模式来说,很重要的一个方面是:利用这些设计模式可以很容易地做出修改.与其他模式一样,状态模式也很易于更新和改变.下面在这个灯的示例上再加两个状态:更亮(Brighter)和最亮(Brightest)
现在变成了4个状态,序列有所改变.'关'(off)状态只能变到"开"(on)状态,on状态不能变到off状态.on状态只能变到"更亮"(brighter)状态和"最亮"(brightest)状态.只能最亮状态才可能变到关状态.
改变接口
要改变的第一个参与者是接口IState,这个接口中必须指定相应的方法,可以用来迁移到brighter和brightest状态.
IState.php
现在所有状态类都必须包含这4个方法,它们都需要结合到Light类中.
改变状态
状态设计模式中有改变时,这些新增的改变会对模式整体的其他方面带来影响.不过,增加改变相当简单,每个状态只有一个特定的变迁.
四个状态
OnState.php
light=$light; } publicfunctionturnLightOn() { echo"不合法的操作!
"; } publicfunctionturnLightOff() { echo"灯关闭!看不见帅哥chenqionghe了!
"; $this->light->setState($this->light->getOffState()); } publicfunctionturnBrighter() { echo"灯更亮了,看帅哥chenqionghe看得更真切了!
"; $this->light->setState($this->light->getBrighterState()); } publicfunctionturnBrightest() { echo"不合法的操作!
"; } }OffState.php
light=$light; } publicfunctionturnLightOn() { echo"灯打开!可以看见帅哥chenqionghe了!
"; $this->light->setState($this->light->getOnState()); } publicfunctionturnLightOff() { echo"不合法的操作!
"; } publicfunctionturnBrighter() { echo"不合法的操作!
"; } publicfunctionturnBrightest() { echo"不合法的操作!
"; } }Brighter.php
light=$light; } publicfunctionturnLightOn() { echo"不合法的操作!
"; } publicfunctionturnLightOff() { echo"不合法的操作!
"; } publicfunctionturnBrighter() { echo"不合法的操作!
"; } publicfunctionturnBrightest() { echo"灯最亮了,看帅哥chenqionghe已经帅到无敌!
"; $this->light->setState($this->light->getBrightestState()); } }Brightest.php
light=$light; } publicfunctionturnLightOn() { echo"灯已经打开了->不做操作
"; } publicfunctionturnLightOff() { echo"灯关闭!看不见帅哥chenqionghe了!
"; $this->light->setState($this->light->getOffState()); } publicfunctionturnBrighter() { echo"不合法的操作!
"; } publicfunctionturnBrightest() { echo"不合法的操作!
"; } }更新Light类
Light.php
offState=newOffState($this); $this->onState=newOnState($this); $this->brighterState=newBrighterState($this); $this->brightestState=newBrightestState($this); //开始状态为关闭状态Off $this->currentState=$this->offState; } //调用状态方法触发器 publicfunctionturnLightOn() { $this->currentState->turnLightOn(); } publicfunctionturnLightOff() { $this->currentState->turnLightOff(); } publicfunctionturnLightBrighter() { $this->currentState->turnBrighter(); } publicfunctionturnLigthBrightest() { $this->currentState->turnBrightest(); } //设置当前状态 publicfunctionsetState(IState$state) { $this->currentState=$state; } //获取状态 publicfunctiongetOnState() { return$this->onState; } publicfunctiongetOffState() { return$this->offState; } publicfunctiongetBrighterState() { return$this->brighterState; } publicfunctiongetBrightestState() { return$this->brightestState; } }更新客户
light=newLight(); $this->light->turnLightOn(); $this->light->turnLightBrighter(); $this->light->turnLigthBrightest(); $this->light->turnLightOff(); $this->light->turnLigthBrightest(); } } $worker=newClient();运行结果如下
灯打开!可以看见帅哥chenqionghe了!
灯更亮了,看帅哥chenqionghe看得更真切了!
灯最亮了,看帅哥chenqionghe已经帅到无敌!
灯关闭!看不见帅哥chenqionghe了!
不合法的操作!九宫格移动示例
九宫格的移动分为4个移动:
上(Up)
下(Down)
左(Left)
右(Right)对于这些移动,规则是要求单元格之间不能沿对角线方向移动.另外,从一个单元格移动到下一个单元格时,一次只能移动一个单元格
要使用状态设计模式来建立一个九宫格移动示例,
建立接口
IMatrix.php
虽然这个状态设计模式有9个状态,分别对应九个单元格,但一个状态最多只需要4个变迁
上下文
对于状态中的4个变迁或移动方法,上下文必须提供相应方法来调用这些变迁方法,另外还要完成各个状态的实例化.
Context.php
cell1=newCell1State($this); $this->cell2=newCell2State($this); $this->cell3=newCell3State($this); $this->cell4=newCell4State($this); $this->cell5=newCell5State($this); $this->cell6=newCell6State($this); $this->cell7=newCell7State($this); $this->cell8=newCell8State($this); $this->cell9=newCell9State($this); $this->currentState=$this->cell5; } //调用方法 publicfunctiondoUp() { $this->currentState->goUp(); } publicfunctiondoDown() { $this->currentState->goDown(); } publicfunctiondoLeft() { $this->currentState->goLeft(); } publicfunctiondoRight() { $this->currentState->goRight(); } //设置当前状态 publicfunctionsetState(IMatrix$state) { $this->currentState=$state; } //获取状态 publicfunctiongetCell1State() { return$this->cell1; } publicfunctiongetCell2State() { return$this->cell2; } publicfunctiongetCell3State() { return$this->cell3; } publicfunctiongetCell4State() { return$this->cell4; } publicfunctiongetCell5State() { return$this->cell5; } publicfunctiongetCell6State() { return$this->cell6; } publicfunctiongetCell7State() { return$this->cell7; } publicfunctiongetCell8State() { return$this->cell8; } publicfunctiongetCell9State() { return$this->cell9; } }状态
9个状态表示九宫格中的不同单元格,为了唯一显示单元格,会分别输出相应到达的单元格数字,这样能够更清楚地看出穿过矩阵的路线.
Cell1State
context=$contextNow; } publicfunctiongoLeft() { echo'不合法的移动!
'; } publicfunctiongoRight() { echo'走到2
'; $this->context->setState($this->context->getCell2State()); } publicfunctiongoUp() { echo'不合法的移动!
'; } publicfunctiongoDown() { echo'走到4
'; $this->context->setState($this->context->getCell4State()); } }Cell2State
context=$contextNow; } publicfunctiongoLeft() { echo'走到1
'; $this->context->setState($this->context->getCell1State()); } publicfunctiongoRight() { echo'走到3
'; $this->context->setState($this->context->getCell3State()); } publicfunctiongoUp() { echo'不合法的移动!
'; } publicfunctiongoDown() { echo'走到5
'; $this->context->setState($this->context->getCell5State()); } }Cell3State
context=$contextNow; } publicfunctiongoLeft() { echo'走到2
'; $this->context->setState($this->context->getCell2State()); } publicfunctiongoRight() { echo'不合法的移动!
'; } publicfunctiongoUp() { echo'不合法的移动!
'; } publicfunctiongoDown() { echo'走到6
'; $this->context->setState($this->context->getCell6State()); } }Cell4State
context=$contextNow; } publicfunctiongoLeft() { echo'不合法的移动!
'; } publicfunctiongoRight() { echo'走到5
'; $this->context->setState($this->context->getCell5State()); } publicfunctiongoUp() { echo'走到1
'; $this->context->setState($this->context->getCell1State()); } publicfunctiongoDown() { echo'走到7
'; $this->context->setState($this->context->getCell7State()); } }Cell5State
context=$contextNow; } publicfunctiongoLeft() { echo'走到4
'; $this->context->setState($this->context->getCell4State()); } publicfunctiongoRight() { echo'走到6
'; $this->context->setState($this->context->getCell6State()); } publicfunctiongoUp() { echo'走到2
'; $this->context->setState($this->context->getCell2State()); } publicfunctiongoDown() { echo'走到8
'; $this->context->setState($this->context->getCell8State()); } }Cell6State
context=$contextNow; } publicfunctiongoLeft() { echo'走到5
'; $this->context->setState($this->context->getCell5State()); } publicfunctiongoRight() { echo'不合法的移动!
'; } publicfunctiongoUp() { echo'走到3
'; $this->context->setState($this->context->getCell3State()); } publicfunctiongoDown() { echo'走到9
'; $this->context->setState($this->context->getCell9State()); } }Cell7State
context=$contextNow; } publicfunctiongoLeft() { echo'不合法的移动!
'; } publicfunctiongoRight() { echo'走到8
'; $this->context->setState($this->context->getCell8State()); } publicfunctiongoUp() { echo'走到4
'; $this->context->setState($this->context->getCell4State()); } publicfunctiongoDown() { echo'不合法的移动!
'; } }Cell8State
context=$contextNow; } publicfunctiongoLeft() { echo'走到7
'; $this->context->setState($this->context->getCell7State()); } publicfunctiongoRight() { echo'走到9
'; $this->context->setState($this->context->getCell9State()); } publicfunctiongoUp() { echo'走到5
'; $this->context->setState($this->context->getCell5State()); } publicfunctiongoDown() { echo'不合法的移动!
'; } }Cell9State
context=$contextNow; } publicfunctiongoLeft() { echo'走到8
'; $this->context->setState($this->context->getCell8State()); } publicfunctiongoRight() { echo'不合法的移动!
'; } publicfunctiongoUp() { echo'走到6
'; $this->context->setState($this->context->getCell6State()); } publicfunctiongoDown() { echo'不合法的移动!
'; } }要想有效地使用状态设计模式,真正的难点在于要想象现实或模拟世界是怎么样
客户Client
下面从单元格5开始进行一个上,右,下,下,左,上的移动
Client.php
context=newContext(); $this->context->doUp(); $this->context->doRight(); $this->context->doDown(); $this->context->doDown(); $this->context->doLeft(); $this->context->doUp(); } } $worker=newClient();运行结果如下
走到2
走到3
走到6
走到9
走到8
走到5状态模式与PHP
很多人把状态设计模式看做是实现模拟器和游戏的主要方法.总的说来,这确实是状态模式的目标,不过险些之外,状态模型(状态引擎)和状态设计模式在PHP中也有很多应用.用PHP完成更大的项目时,包括Facebook和WordPress,会有更多的新增特性和当前状态需求.对于这种不断有改变和增长的情况,就可以采用可扩展的状态模式来管理.
PHP开发人员如何创建包含多个状态的程序,将决定状态模式的使用范围.所以不仅状态机在游戏和模拟世界中有很多应用,实际上状态模型还有更多适用的领域.只要PHP程序的用户会用到一组有限的状态,开发人员就可以使用状态设计模式.
更多关于PHP相关内容感兴趣的读者可查看本站专题:《php面向对象程序设计入门教程》、《PHP基本语法入门教程》、《PHP数组(Array)操作技巧大全》、《php字符串(string)用法总结》、《php+mysql数据库操作入门教程》及《php常见数据库操作技巧汇总》
希望本文所述对大家PHP程序设计有所帮助。