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


Posted in PHP onApril 02, 2018

本文实例讲述了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 相关文章推荐
web目录下不应该存在多余的程序(安全考虑)
May 09 PHP
一个php短网址的生成代码(仿微博短网址)
May 07 PHP
Destoon实现多表查询示例
Aug 21 PHP
php格式化时间戳显示友好的时间实现思路及代码
Oct 23 PHP
支持中文、字母、数字的PHP验证码
May 04 PHP
php三种实现多线程类似的方法
Oct 30 PHP
使用Composer安装Yii框架的方法
Mar 15 PHP
PHP中的密码加密的解决方案总结
Oct 26 PHP
PHP在弹框中获取foreach中遍历的id值并传递给地址栏
Jun 13 PHP
PHP基于ORM方式操作MySQL数据库实例
Jun 21 PHP
PHP排序算法之冒泡排序(Bubble Sort)实现方法详解
Apr 20 PHP
php去除deprecated的实例方法
Nov 17 PHP
PHP设计模式之模板方法模式定义与用法详解
Apr 02 #PHP
PHP实现动态获取函数参数的方法示例
Apr 02 #PHP
PHP调用其他文件中的类
Apr 02 #PHP
为何说PHP引用是个坑,要慎用
Apr 02 #PHP
PHP实现的一致性Hash算法详解【分布式算法】
Mar 31 #PHP
PHP实现基于PDO扩展连接PostgreSQL对象关系数据库示例
Mar 31 #PHP
ThinkPHP框架中使用Memcached缓存数据的方法
Mar 31 #PHP
You might like
用ADODB来让PHP操作ACCESS数据库的方法
2006/12/31 PHP
PHP 多维数组排序(usort,uasort)
2010/06/30 PHP
检查用户名是否已在mysql中存在的php写法
2014/01/20 PHP
smarty模板引擎使用内建函数foreach循环取出所有数组值的方法
2015/01/22 PHP
PHP的swoole扩展安装方法详细教程
2016/05/18 PHP
PHP针对伪静态的注入总结【附asp与Python相关代码】
2017/08/01 PHP
PHP实现基于状态的责任链审批模式详解
2019/05/31 PHP
JavaScript 定义function的三种方式小结
2009/10/16 Javascript
json数据与字符串的相互转化示例
2013/09/18 Javascript
js每隔5分钟执行一次ajax请求的实现方法
2013/11/27 Javascript
jQuery针对各类元素操作基础教程
2014/08/29 Javascript
jQuery实现点击该行即可删除HTML表格行
2014/10/17 Javascript
js随机生成字母数字组合的字符串 随机动画数字
2015/09/02 Javascript
JavaScript中闭包的写法和作用详解
2016/06/29 Javascript
Angular2 路由问题修复详解
2017/03/01 Javascript
jQuery插件FusionCharts实现的2D饼状图效果【附demo源码下载】
2017/03/03 Javascript
JavaScript实现职责链模式概述
2018/01/25 Javascript
postman+json+springmvc测试批量添加实例
2018/03/31 Javascript
Vue 页面切换效果之 BubbleTransition(推荐)
2018/04/08 Javascript
JavaScript Canvas实现验证码
2020/08/02 Javascript
小程序组件之仿微信通讯录的实现代码
2018/09/12 Javascript
js神秘的电报密码 哈弗曼编码实现
2019/09/10 Javascript
微信小程序实现多行文字超出部分省略号显示功能
2019/10/23 Javascript
HTML元素拖拽功能实现的完整实例
2020/12/04 Javascript
javascript前端实现多视频上传
2020/12/13 Javascript
[03:09]2014DOTA2国际邀请赛 Mushi前队友送上祝福
2014/07/12 DOTA
Python获取央视节目单的实现代码
2015/07/25 Python
python中subprocess批量执行linux命令
2018/04/27 Python
django自带的server 让外网主机访问方法
2018/05/14 Python
python 实现return返回多个值
2019/11/19 Python
python 基于opencv操作摄像头
2020/12/24 Python
HTML5 通信API 跨域门槛将不再高、数据推送也不再是梦
2013/04/25 HTML / CSS
美国知名的隐形眼镜电商:Contacts America
2019/11/19 全球购物
污水厂厂长岗位职责
2014/01/04 职场文书
广告设计应届生求职信
2014/03/01 职场文书
商业计划书之服装
2019/09/09 职场文书