侯体宗的博客
  • 首页
  • 人生(杂谈)
  • 技术
  • 关于我
  • 更多分类
    • 文件下载
    • 文字修仙
    • 中国象棋ai
    • 群聊
    • 九宫格抽奖
    • 拼图
    • 消消乐
    • 相册

PHP设计模式之状态模式定义与用法详解

php  /  管理员 发布于 7年前   162

本文实例讲述了PHP设计模式之状态模式定义与用法。分享给大家供大家参考,具体如下:

什么是状态设计模式

当一个对象的内在状态改变时允许改变其行为,这个对象看起来像是改变了其类。

状态模式主要解决的是当控制一个对象状态的条件表达式过于复杂时的情况。把状态的判断逻辑转移到表示不同状态的一系列类中,可以把复杂的判断逻辑简化。

什么时候使用状态模式

对象中频繁改变非常依赖于条件语句。 就其自身来说, 条件语句本身没有什么问题(如switch语句或带else子句的语句),不过, 如果选项太多, 以到程序开始出现混乱, 或者增加或改变选项需要花费太多时间, 甚至成为一种负担, 这就出现了问题

对于状态设计模式, 每个状态都有自己的具体类, 它们实现一个公共接口. 我们不用查看对象的控制流, 而是从另一个角度来考虑, 即对象的状态.

状态机是一个模型, 其重点包括不同的状态, 一个状态到另一个状态的变迁, 以及导致状态改变的触发器.

以开灯关灯为例子, 状态模型的本质分为3点:

①状态(关灯和开灯)
②变迁(从关灯到开灯, 以及从开灯到关灯)
③触发器(灯开关)

所以状态模式都需要一个参与者来跟踪对象所处的状态. 以Light为例, Light需要知道当前状态是什么.

示例:开灯关灯

Light.php

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

该接口的实现类

OnState.php

light = $light;  }  public function turnLightOn()  {    echo "灯已经打开了->不做操作
"; } public function turnLightOff() { echo "灯关闭!看不见帅哥chenqionghe了!
"; $this->light->setState($this->light->getOffState()); }}

OffState.php

light = $light;  }  public function turnLightOn()  {    echo "灯打开!可以看见帅哥chenqionghe了!
"; $this->light->setState($this->light->getOnState()); } public function turnLightOff() { echo "灯已经关闭了->不做操作
"; }}

默认状态是OffState, 它必须实现IState方法turnLightOn和turnLightOff, Light调用turnLightOn方法, 会显示(灯打开!可以看见帅哥chenqionghe了), 然后将OnState设置为当前状态, 不过,如果是调用 OffState的turnLightOff方法, 就只有提示灯已经被关闭了 不会有其他动作.

客户

Client的所有请求都是通过Light发出, Client和任何状态类之间都没有直接连接, 包括IState接口.下面的Client显示了触发两个状态中所有方法的请求.

Client.php

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

现在所有状态类都必须包含这4个方法, 它们都需要结合到Light类中.

改变状态

状态设计模式中有改变时, 这些新增的改变会对模式整体的其他方面带来影响. 不过, 增加改变相当简单, 每个状态只有一个特定的变迁.

四个状态

OnState.php

light = $light;  }  public function turnLightOn()  {    echo "不合法的操作!
"; } public function turnLightOff() { echo "灯关闭!看不见帅哥chenqionghe了!
"; $this->light->setState($this->light->getOffState()); } public function turnBrighter() { echo "灯更亮了, 看帅哥chenqionghe看得更真切了!
"; $this->light->setState($this->light->getBrighterState()); } public function turnBrightest() { echo "不合法的操作!
"; }}

OffState.php

light = $light;  }  public function turnLightOn()  {    echo "灯打开!可以看见帅哥chenqionghe了!
"; $this->light->setState($this->light->getOnState()); } public function turnLightOff() { echo "不合法的操作!
"; } public function turnBrighter() { echo "不合法的操作!
"; } public function turnBrightest() { echo "不合法的操作!
"; }}

Brighter.php

light = $light;  }  public function turnLightOn()  {    echo "不合法的操作!
"; } public function turnLightOff() { echo "不合法的操作!
"; } public function turnBrighter() { echo "不合法的操作!
"; } public function turnBrightest() { echo "灯最亮了, 看帅哥chenqionghe已经帅到无敌!
"; $this->light->setState($this->light->getBrightestState()); }}

Brightest.php

light = $light;  }  public function turnLightOn()  {    echo "灯已经打开了->不做操作
"; } public function turnLightOff() { echo "灯关闭!看不见帅哥chenqionghe了!
"; $this->light->setState($this->light->getOffState()); } public function turnBrighter() { echo "不合法的操作!
"; } public function turnBrightest() { echo "不合法的操作!
"; }}

更新Light类

Light.php

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;  }}

更新客户

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

虽然这个状态设计模式有9个状态, 分别对应九个单元格, 但一个状态最多只需要4个变迁

上下文

对于状态中的4个变迁或移动方法, 上下文必须提供相应方法来调用这些变迁方法, 另外还要完成各个状态的实例化.

Context.php

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

context = $contextNow;  }  public function goLeft()  {    echo '不合法的移动!
'; } public function goRight() { echo '走到2
'; $this->context->setState($this->context->getCell2State()); } public function goUp() { echo '不合法的移动!
'; } public function goDown() { echo '走到4
'; $this->context->setState($this->context->getCell4State()); }}

Cell2State

context = $contextNow;  }  public function goLeft()  {    echo '走到1
'; $this->context->setState($this->context->getCell1State()); } public function goRight() { echo '走到3
'; $this->context->setState($this->context->getCell3State()); } public function goUp() { echo '不合法的移动!
'; } public function goDown() { echo '走到5
'; $this->context->setState($this->context->getCell5State()); }}

Cell3State

context = $contextNow;  }  public function goLeft()  {    echo '走到2
'; $this->context->setState($this->context->getCell2State()); } public function goRight() { echo '不合法的移动!
'; } public function goUp() { echo '不合法的移动!
'; } public function goDown() { echo '走到6
'; $this->context->setState($this->context->getCell6State()); }}

Cell4State

context = $contextNow;  }  public function goLeft()  {    echo '不合法的移动!
'; } public function goRight() { echo '走到5
'; $this->context->setState($this->context->getCell5State()); } public function goUp() { echo '走到1
'; $this->context->setState($this->context->getCell1State()); } public function goDown() { echo '走到7
'; $this->context->setState($this->context->getCell7State()); }}

Cell5State

context = $contextNow;  }  public function goLeft()  {    echo '走到4
'; $this->context->setState($this->context->getCell4State()); } public function goRight() { echo '走到6
'; $this->context->setState($this->context->getCell6State()); } public function goUp() { echo '走到2
'; $this->context->setState($this->context->getCell2State()); } public function goDown() { echo '走到8
'; $this->context->setState($this->context->getCell8State()); }}

Cell6State

context = $contextNow;  }  public function goLeft()  {    echo '走到5
'; $this->context->setState($this->context->getCell5State()); } public function goRight() { echo '不合法的移动!
'; } public function goUp() { echo '走到3
'; $this->context->setState($this->context->getCell3State()); } public function goDown() { echo '走到9
'; $this->context->setState($this->context->getCell9State()); }}

Cell7State

context = $contextNow;  }  public function goLeft()  {    echo '不合法的移动!
'; } public function goRight() { echo '走到8
'; $this->context->setState($this->context->getCell8State()); } public function goUp() { echo '走到4
'; $this->context->setState($this->context->getCell4State()); } public function goDown() { echo '不合法的移动!
'; }}

Cell8State

context = $contextNow;  }  public function goLeft()  {    echo '走到7
'; $this->context->setState($this->context->getCell7State()); } public function goRight() { echo '走到9
'; $this->context->setState($this->context->getCell9State()); } public function goUp() { echo '走到5
'; $this->context->setState($this->context->getCell5State()); } public function goDown() { echo '不合法的移动!
'; }}

Cell9State

context = $contextNow;  }  public function goLeft()  {    echo '走到8
'; $this->context->setState($this->context->getCell8State()); } public function goRight() { echo '不合法的移动!
'; } public function goUp() { echo '走到6
'; $this->context->setState($this->context->getCell6State()); } public function goDown() { echo '不合法的移动!
'; }}

要想有效地使用状态设计模式, 真正的难点在于要想象现实或模拟世界是怎么样

客户Client

下面从单元格5开始进行一个上,右,下, 下,左,上的移动

Client.php

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基本语法入门教程》、《PHP数组(Array)操作技巧大全》、《php字符串(string)用法总结》、《php+mysql数据库操作入门教程》及《php常见数据库操作技巧汇总》

希望本文所述对大家PHP程序设计有所帮助。

您可能感兴趣的文章:

  • PHP设计模式之责任链模式的深入解析
  • 简单介绍PHP的责任链编程模式
  • php+ajax发起流程和审核流程(以请假为例)
  • php注册审核重点解析(数据访问)
  • 如何用PHP做到页面注册审核
  • PHP代码审核的详细介绍
  • 学习php设计模式 php实现状态模式
  • 详解PHP中的状态模式编程
  • php设计模式 State (状态模式)
  • PHP实现基于状态的责任链审批模式详解


  • 上一条:
    PHP设计模式之装饰器模式定义与用法详解
    下一条:
    PHP设计模式之模板方法模式定义与用法详解
  • 昵称:

    邮箱:

    0条评论 (评论内容有缓存机制,请悉知!)
    最新最热
    • 分类目录
    • 人生(杂谈)
    • 技术
    • linux
    • Java
    • php
    • 框架(架构)
    • 前端
    • ThinkPHP
    • 数据库
    • 微信(小程序)
    • Laravel
    • Redis
    • Docker
    • Go
    • swoole
    • Windows
    • Python
    • 苹果(mac/ios)
    • 相关文章
    • Laravel从Accel获得5700万美元A轮融资(0个评论)
    • PHP 8.4 Alpha 1现已发布!(0个评论)
    • 用Time Warden监控PHP中的代码处理时间(0个评论)
    • 在PHP中使用array_pop + yield实现读取超大型目录功能示例(0个评论)
    • Property Hooks RFC在PHP 8.4中越来越接近现实(0个评论)
    • 近期文章
    • 在windows10中升级go版本至1.24后LiteIDE的Ctrl+左击无法跳转问题解决方案(0个评论)
    • 智能合约Solidity学习CryptoZombie第四课:僵尸作战系统(0个评论)
    • 智能合约Solidity学习CryptoZombie第三课:组建僵尸军队(高级Solidity理论)(0个评论)
    • 智能合约Solidity学习CryptoZombie第二课:让你的僵尸猎食(0个评论)
    • 智能合约Solidity学习CryptoZombie第一课:生成一只你的僵尸(0个评论)
    • 在go中实现一个常用的先进先出的缓存淘汰算法示例代码(0个评论)
    • 在go+gin中使用"github.com/skip2/go-qrcode"实现url转二维码功能(0个评论)
    • 在go语言中使用api.geonames.org接口实现根据国际邮政编码获取地址信息功能(1个评论)
    • 在go语言中使用github.com/signintech/gopdf实现生成pdf分页文件功能(95个评论)
    • gmail发邮件报错:534 5.7.9 Application-specific password required...解决方案(0个评论)
    • 近期评论
    • 122 在

      学历:一种延缓就业设计,生活需求下的权衡之选中评论 工作几年后,报名考研了,到现在还没认真学习备考,迷茫中。作为一名北漂互联网打工人..
    • 123 在

      Clash for Windows作者删库跑路了,github已404中评论 按理说只要你在国内,所有的流量进出都在监控范围内,不管你怎么隐藏也没用,想搞你分..
    • 原梓番博客 在

      在Laravel框架中使用模型Model分表最简单的方法中评论 好久好久都没看友情链接申请了,今天刚看,已经添加。..
    • 博主 在

      佛跳墙vpn软件不会用?上不了网?佛跳墙vpn常见问题以及解决办法中评论 @1111老铁这个不行了,可以看看近期评论的其他文章..
    • 1111 在

      佛跳墙vpn软件不会用?上不了网?佛跳墙vpn常见问题以及解决办法中评论 网站不能打开,博主百忙中能否发个APP下载链接,佛跳墙或极光..
    • 2016-10
    • 2016-11
    • 2017-06
    • 2017-07
    • 2017-08
    • 2017-09
    • 2017-11
    • 2017-12
    • 2018-01
    • 2018-02
    • 2018-03
    • 2020-03
    • 2020-04
    • 2020-05
    • 2020-06
    • 2020-07
    • 2020-09
    • 2021-02
    • 2021-03
    • 2021-04
    • 2021-05
    • 2021-06
    • 2021-07
    • 2021-08
    • 2021-09
    • 2021-10
    • 2021-11
    • 2021-12
    • 2022-01
    • 2022-02
    • 2022-05
    • 2022-06
    • 2022-07
    • 2022-08
    • 2022-09
    • 2022-10
    • 2022-11
    • 2022-12
    • 2023-01
    • 2023-02
    • 2023-03
    • 2023-04
    • 2023-05
    • 2023-06
    • 2023-07
    • 2023-08
    • 2023-09
    • 2023-10
    • 2023-11
    • 2023-12
    • 2024-01
    • 2024-02
    • 2024-03
    • 2024-04
    • 2024-05
    • 2024-06
    • 2024-07
    • 2024-09
    Top

    Copyright·© 2019 侯体宗版权所有· 粤ICP备20027696号 PHP交流群

    侯体宗的博客