PHP设计模式入门之状态模式原理与实现方法分析


Posted in PHP onApril 26, 2020

本文实例讲述了PHP设计模式入门之状态模式原理与实现方法。分享给大家供大家参考,具体如下:

想必大家都用过自动售卖的自动饮料机吧,塞入硬币或纸币,选择想要的饮料,饮料就会在机器的下方滚出。大家有没有相关如果用程序去写一个饮料机要怎么样实现呢?

首先我们可以分享一下这部饮料机有几种状态

一、没有钱的状态

二、有钱的状态

三、售出的状态

四、销售一空的状态

好吧,知道了这些状态之后我们开始写代码了!

JuiceMachine.php

<?php
/**
 * 饮料机
 * @author ben
 *
 */
class JuiceMachine{
 /**
 * 糖果机一共存在四种状态:没钱,有钱,成功售出以及销售一空
 * 
 * 没钱的状态
 * @var INT
 */
 const NOMONEY = 0;
 
 /**
 * 有钱的状态
 * @var INT
 */
 const HASMONEY = 1;
 
 /**
 * 成功售出的状态
 * @var INT
 */
 const SOLD = 2;
 
 /**
 * 销售一空的状态
 * @var INT
 */
 const SOLDOUT = 3;
 
 /**
 * 记录糖果机当前的状态,初始化状态为售空
 * @var INT
 */
 private $_state = JuiceMachine::SOLDOUT;
 
 /**
 * 该变量用于记录饮料机中饮料的数量
 */
 private $_count; 
 
 /**
 * 构造方法,最主要是用来初始化count和state属性的
 */
 public function __construct($count){
   $this->_count = $count;
   //当饮料机中的饮料数量大于零时,将饮料机的状态重置为没有钱的状态。
   if($this->_count > 0){
     $this->_state = JuiceMachine::NOMONEY;
   }
 }
 
 /**
 * 投入硬币
 */
 public function insertCoin(){
   if($this->_state == JuiceMachine::HASMONEY ){
     echo "you can't insert another coin!<br />";
   }elseif($this->_state == JuiceMachine::NOMONEY){
     echo "you just insert a coin<br />";
     $this->_state = JuiceMachine::HASMONEY;
   }elseif($this->_state == JuiceMachine::SOLD){
     echo "wait a minute, we are giving you a bottle of juice<br />";
   }elseif($this->_state == JuiceMachine::SOLDOUT){
     echo "you can't insert coin, the machine is already soldout<br />";
   }
 }
 
 /**
 * 退回硬币
 */
 public function retreatCoin(){
   if($this->_state == JuiceMachine::HASMONEY ){
     echo "coin return!<br />";
     $this->_state = JuiceMachine::NOMONEY;
   }elseif($this->_state == JuiceMachine::NOMONEY){
     echo "you have'nt inserted a coin yet<br />";
   }elseif($this->_state == JuiceMachine::SOLD){
     echo "sorry, you already clicked the botton<br />";
   }elseif($this->_state == JuiceMachine::SOLDOUT){
     echo "you have'nt inserted a coin yet<br />";
   }
 }
 
 /**
 * 点击饮料对应的按钮
 */
 public function clickButton(){
   if($this->_state == JuiceMachine::HASMONEY ){
     echo "you clicked, we are giving you a bottle of juice...<br />";
     $this->_state = JuiceMachine::SOLD;  //改变饮料机的状态为售出模式
     $this->dispend();
   }elseif($this->_state == JuiceMachine::NOMONEY){
     echo "you clicked,but you hav'nt inserted a coin yet<br />";
   }elseif($this->_state == JuiceMachine::SOLD){
     echo "click twice does'nt get you two bottle of juice<br />";
   }elseif($this->_state == JuiceMachine::SOLDOUT){
     echo "you clicked, but the machine is already soldout<br />";
   }
 }
 
 /**
 * 发放饮料
 */
 public function dispend(){
   if($this->_state == JuiceMachine::HASMONEY ){
     echo "please click the button first<br />";
   }elseif($this->_state == JuiceMachine::NOMONEY){
     echo "you need to pay first<br />";
   }elseif($this->_state == JuiceMachine::SOLD){
     echo "now you get you juice<br />";
     //饮料机中的饮料数量减一
     $this->_count--;
     if($this->_count <= 0){
       echo "opps, runing out of juice<br />";
       //如果这时饮料机中没有饮料了,将饮料机的状态重置为销售一空
       $this->_state = JuiceMachine::SOLDOUT;
     }else{
       //将饮料机的状态重置为没有钱
       $this->_state = JuiceMachine::NOMONEY;
     }
   }elseif($this->_state == JuiceMachine::SOLDOUT){
     //其实这种情况不应该出现
     echo "opps, it appears that we don't have any juice left<br />";
   }
 }
}

index.php

<?php
require_once 'JuiceMachine.php';
 
$juiceMachine = new JuiceMachine(1);
 
$juiceMachine->insertCoin();
$juiceMachine->clickButton();

运行的结果是:

you just insert a coin
you clicked, we are giving you a bottle of juice...
now you get you juice
opps, runing out of juice

到目前为止我们的程序运行良好,没有出现什么问题,但是从这些多重的if判断中你是否嗅到了坏代码的味道呢?有一天问题终于出现了,老板希望当用户点击按钮时有10%的概率拿到两瓶饮料,我们需要为饮料机多加一个状态,这时去修改代码就成为了一种灾难,而且很可能会影响到之前的代码,带来新的bug,看看状态模式如何帮助我们度过难关吧!

状态模式的官方定义是:状态模式允许对象在内部状态改变是改变它的行为,对象看起来好像是修改了它的类

用uml类图表示如下:

PHP设计模式入门之状态模式原理与实现方法分析

在我们这个项目中的实际类图如下:

PHP设计模式入门之状态模式原理与实现方法分析

具体实现代码:

State.php

<?php
interface State{
  
  /**
   * 插入硬币
   */
  public function insertCoin();
  
  /**
   * 回退硬币
   */
  public function retreatCoin();
  
  /**
   * 点击按钮
   */
  public function clickButton();
  
  /**
   * 发放饮料
   */
  public function dispend();
}

NomoneyState.php

<?php
require_once 'State.php';
class NomoneyState implements State{
  
  /**
   * 饮料机的实例
   * 
   * @var object
   */
  private $_juiceMachine;
  
  /**
   * 构造方法,主要用于初始化饮料机实例
   * 
   */
  public function __construct($juiceMachine){
    $this->_juiceMachine = $juiceMachine;
  }
  
 /* (non-PHPdoc)
   * @see State::insertCoin()
   */
  public function insertCoin()
  {
    // TODO Auto-generated method stub
    echo "you just insert a coin<br />";
    //将饮料机的状态切换成有钱的状态
    $this->_juiceMachine->setState($this->_juiceMachine->getHasmoneyState());
  }
 
 /* (non-PHPdoc)
   * @see State::retreatCoin()
   */
  public function retreatCoin()
  {
    // TODO Auto-generated method stub
    echo "you have'nt inserted a coin yet<br />";
  }
 
 /* (non-PHPdoc)
   * @see State::clickButton()
   */
  public function clickButton()
  {
    // TODO Auto-generated method stub
    echo "you clicked,but you hav'nt inserted a coin yet<br />";
  }
 
 /* (non-PHPdoc)
   * @see State::dispend()
   */
  public function dispend()
  {
    // TODO Auto-generated method stub
    echo "you need to pay first<br />";
  }
}

HasmoneyState.php

<?php
require_once 'State.php';
 
class HasmoneyState implements State
{
 
  /**
   * 饮料机的实例
   *
   * @var object
   */
  private $_juiceMachine;
 
  /**
   * 构造方法,主要用于初始化饮料机实例
   */
  public function __construct($juiceMachine)
  {
    $this->_juiceMachine = $juiceMachine;
  }
  
  /*
   * (non-PHPdoc) @see State::insertCoin()
   */
  public function insertCoin()
  {
    // TODO Auto-generated method stub
    echo "you can't insert another coin!<br />";
  }
  
  /*
   * (non-PHPdoc) @see State::retreatCoin()
   */
  public function retreatCoin()
  {
    // TODO Auto-generated method stub
    echo "coin return!<br />";
    $this->_juiceMachine->setState($this->_juiceMachine->getNomoneyState());
  }
  
  /*
   * (non-PHPdoc) @see State::clickButton()
   */
  public function clickButton()
  {
    // TODO Auto-generated method stub
    echo "you clicked, we are giving you a bottle of juice...<br />";
    // 改变饮料机的状态为售出模式
    $rand = mt_rand(0, 0);
    // 当随机数为0(即1/10的概率)并且饮料机中还有1瓶以上的饮料时
    if ($rand == 0 && $this->_juiceMachine->getCount() > 1) {
      $this->_juiceMachine->setState($this->_juiceMachine->getWinnerState());
    } else {
      $this->_juiceMachine->setState($this->_juiceMachine->getSoldState());
    }
  }
  
  /*
   * (non-PHPdoc) @see State::dispend()
   */
  public function dispend()
  {
    // TODO Auto-generated method stub
    echo "please click the button first<br />";
  }
}

SoldoutState.php

<?php
require_once 'State.php';
class SoldoutState implements State{
  
  /**
   * 饮料机的实例
   *
   * @var object
   */
  private $_juiceMachine;
  
  /**
   * 构造方法,主要用于初始化饮料机实例
   *
   */
  public function __construct($juiceMachine){
    $this->_juiceMachine = $juiceMachine;
  }
  
 /* (non-PHPdoc)
   * @see State::insertCoin()
   */
  public function insertCoin()
  {
    // TODO Auto-generated method stub
    echo "you can't insert coin, the machine is already soldout<br />";
  }
 
 /* (non-PHPdoc)
   * @see State::retreatCoin()
   */
  public function retreatCoin()
  {
    // TODO Auto-generated method stub
    echo "you have'nt inserted a coin yet<br />";
  }
 
 /* (non-PHPdoc)
   * @see State::clickButton()
   */
  public function clickButton()
  {
    // TODO Auto-generated method stub
    echo "you clicked, but the machine is already soldout<br />";
  }
 
 /* (non-PHPdoc)
   * @see State::dispend()
   */
  public function dispend()
  {
    // TODO Auto-generated method stub
    echo "opps, it appears that we don't have any juice left<br />";
  }
}

SoldState.php

<?php
require_once 'State.php';
class SoldState implements State{
  
  /**
   * 饮料机的实例
   *
   * @var object
   */
  private $_juiceMachine;
  
  /**
   * 构造方法,主要用于初始化饮料机实例
   *
   */
  public function __construct($juiceMachine){
    $this->_juiceMachine = $juiceMachine;
  }
  
 /* (non-PHPdoc)
   * @see State::insertCoin()
   */
  public function insertCoin()
  {
    // TODO Auto-generated method stub
    echo "wait a minute, we are giving you a bottle of juice<br />";
  }
 
 /* (non-PHPdoc)
   * @see State::retreatCoin()
   */
  public function retreatCoin()
  {
    // TODO Auto-generated method stub
    echo "sorry, you already clicked the botton<br />";
  }
 
 /* (non-PHPdoc)
   * @see State::clickButton()
   */
  public function clickButton()
  {
    // TODO Auto-generated method stub
    echo "click twice does'nt get you two bottle of juice<br />";
  }
 
 /* (non-PHPdoc)
   * @see State::dispend()
   */
  public function dispend()
  {
    $this->_juiceMachine->decJuice();
    if($this->_juiceMachine->getCount() <= 0){
      echo "opps, runing out of juice<br />";
      //如果这时饮料机中没有饮料了,将饮料机的状态重置为销售一空
       $this->_juiceMachine->setState($this->_juiceMachine->getSoldoutState());
    }else{
      //将饮料机的状态重置为没有钱
       $this->_juiceMachine->setState($this->_juiceMachine->getNomoneyState());
    }
  }
  
}

WinnerState.php

<?php
require_once 'State.php';
 
class WinnerState implements State
{
 
  /**
   * 饮料机的实例
   *
   * @var object
   */
  private $_juiceMachine;
 
  /**
   * 构造方法,主要用于初始化饮料机实例
   */
  public function __construct($juiceMachine)
  {
    $this->_juiceMachine = $juiceMachine;
  }
  
  /*
   * (non-PHPdoc) @see State::insertCoin()
   */
  public function insertCoin()
  {
    // TODO Auto-generated method stub
    echo "wait a minute, we are giving you a bottle of juice<br />";
  }
  
  /*
   * (non-PHPdoc) @see State::retreatCoin()
   */
  public function retreatCoin()
  {
    // TODO Auto-generated method stub
    echo "sorry, you already clicked the botton<br />";
  }
  
  /*
   * (non-PHPdoc) @see State::clickButton()
   */
  public function clickButton()
  {
    // TODO Auto-generated method stub
    echo "click twice does'nt get you two bottle of juice<br />";
  }
  
  /*
   * (non-PHPdoc) @see State::dispend()
   */
  public function dispend()
  {
    echo "you are a winner! you get two bottle of juice!<br />";
    $this->_juiceMachine->decJuice();
    if ($this->_juiceMachine->getCount() > 0) {
      $this->_juiceMachine->decJuice();
      if ($this->_juiceMachine->getCount() <= 0) {
        echo "opps, runing out of juice<br />";
        // 如果这时饮料机中没有饮料了,将饮料机的状态重置为销售一空
        $this->_juiceMachine->setState($this->_juiceMachine->getSoldoutState());
      } else {
        // 将饮料机的状态重置为没有钱
        $this->_juiceMachine->setState($this->_juiceMachine->getSoldoutState());
      }
    } else {
      echo "opps, runing out of juice<br />";
      // 如果这时饮料机中没有饮料了,将饮料机的状态重置为销售一空
      $this->_juiceMachine->setState($this->_juiceMachine->getSoldoutState());
    }
  }
}

JuiceMachine.php

<?php
require_once './state/NomoneyState.php';
require_once './state/HasmoneyState.php';
require_once './state/SoldState.php';
require_once './state/SoldoutState.php';
require_once './state/WinnerState.php';
 
class JuiceMachine
{
 
  /**
   * 记录糖果机当前的状态,初始化状态为售空
   * 
   * @var object
   */
  private $_state;
 
  /**
   * 该变量用于记录饮料机中饮料的数量
   */
  private $_count;
 
  /**
   * 构造方法,最主要是用来初始化count和state属性的
   */
  public function __construct($count)
  {
    $this->_state = new SoldoutState($this);
    $this->_count = $count;
    // 当饮料机中的饮料数量大于零时,将饮料机的状态重置为没有钱的状态。
    if ($this->_count > 0) {
      $this->_state = new NomoneyState($this);
    }
  }
  
  /*
   * (non-PHPdoc) @see State::insertCoin()
   */
  public function insertCoin()
  {
    // TODO Auto-generated method stub
    $this->_state->insertCoin();
  }
  
  /*
   * (non-PHPdoc) @see State::retreatCoin()
   */
  public function retreatCoin()
  {
    // TODO Auto-generated method stub
    $this->_state->retreatCoin();
  }
  
  /*
   * (non-PHPdoc) @see State::clickButton()
   */
  public function clickButton()
  {
    $this->_state->clickButton();
    //其实发放糖果是在用户点击完按钮后机器内部进行的所有没有必要再写一个dispend方法
    $this->_state->dispend();
  }
  
  /**
   * 设置糖果机的状态
   * 
   * @param State $state
   */
  public function setState(State $state)
  {
    $this->_state = $state;
  }
  
  /**
   * 获取没有钱的状态
   */
  public function getNomoneyState(){
    return new NomoneyState($this);
  }
  
  /**
   * 获取有钱的状态
   */
  public function getHasmoneyState(){
    return new HasmoneyState($this);
  }
  
  /**
   * 获取售出的状态
   */
  public function getSoldState(){
    return new SoldState($this);
  }
  
  /**
   * 获取销售一空的状态
   */
  public function getSoldoutState(){
    return new SoldoutState($this);
  }
  
  /**
   * 获取幸运者的状态
   */
  public function getWinnerState(){
    return new WinnerState($this);
  }
  
  /**
   * 获取饮料机中饮料的数量
   */
  public function getCount(){
    return $this->_count;
  }
  
  /**
   * 将饮料数量减一
   */
  public function decJuice(){
    echo "now you get you juice<br />";
    //饮料机中的饮料数量减一
    $this->_count--;
  }
  
}

index.php

<?php
require_once 'JuiceMachine.php';
 
$juiceMachine = new JuiceMachine(2);
 
$juiceMachine->insertCoin();
$juiceMachine->clickButton();

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

PHP 相关文章推荐
中英文字符串翻转函数
Dec 09 PHP
php中全局变量global的使用演示代码
May 18 PHP
PHP 图片上传代码
Sep 13 PHP
Php中文件下载功能实现超详细流程分析
Jun 13 PHP
比较discuz和ecshop的截取字符串函数php版
Sep 03 PHP
PHP实现提取一个图像文件并在浏览器上显示的代码
Oct 06 PHP
php实现微信公众号无限群发
Oct 11 PHP
Symfony2联合查询实现方法
Mar 18 PHP
php使用变量动态创建类的对象用法示例
Feb 06 PHP
PHP经典实用正则表达式小结
May 04 PHP
php实现的错误处理封装类实例
Jun 20 PHP
Symfony查询方法实例小结
Jun 28 PHP
PHP设计模式入门之迭代器模式原理与实现方法分析
Apr 26 #PHP
PHP中迭代器的简单实现及Yii框架中的迭代器实现方法示例
Apr 26 #PHP
PHP设计模式之迭代器模式Iterator实例分析【对象行为型】
Apr 26 #PHP
Yii Framework框架开发微信公众平台示例
Apr 26 #PHP
PHP随机生成中文段落示例【测试网站内容时使用】
Apr 26 #PHP
PHP过滤器 filter_has_var() 函数用法实例分析
Apr 23 #PHP
PHP优化之批量操作MySQL实例分析
Apr 23 #PHP
You might like
使用PHP的日期与时间函数技巧
2008/04/24 PHP
ThinkPHP基于PHPExcel导入Excel文件的方法
2014/10/15 PHP
php自动获取关键字的方法
2015/01/06 PHP
PHP模板引擎Smarty内置变量调解器用法详解
2016/04/11 PHP
jQuery 连续列表实现代码
2009/12/21 Javascript
基于jquery的checkbox下拉框插件代码
2010/06/25 Javascript
基于Jquery的表格隔行换色,移动换色,点击换色插件
2010/12/22 Javascript
Jquery.addClass始终无效原因分析
2013/09/08 Javascript
js每隔5分钟执行一次ajax请求的实现方法
2013/11/27 Javascript
推荐9款炫酷的基于jquery的页面特效
2014/12/07 Javascript
Uploadify上传文件方法
2016/03/16 Javascript
实现easyui的datagrid导出为excel的示例代码
2016/11/10 Javascript
JavaScript实现经典排序算法之冒泡排序
2016/12/28 Javascript
使用 vue-i18n 切换中英文效果
2018/05/23 Javascript
JS实现网页烟花动画效果
2020/03/10 Javascript
js canvas实现俄罗斯方块
2020/10/11 Javascript
pandas 取出表中一列数据所有的值并转换为array类型的方法
2018/04/11 Python
python 动态生成变量名以及动态获取变量的变量名方法
2019/01/20 Python
Django上线部署之IIS的配置方法
2019/08/22 Python
python判断单向链表是否包括环,若包含则计算环入口的节点实例分析
2019/10/23 Python
Python操作多维数组输出和矩阵运算示例
2019/11/28 Python
ONLY瑞典官网:世界知名服装品牌
2018/06/19 全球购物
怎样声明接口
2014/09/19 面试题
经典演讲稿范文
2013/12/30 职场文书
心理健康心得体会
2014/01/02 职场文书
银行简历自我评价
2014/02/11 职场文书
《水乡歌》教学反思
2014/04/24 职场文书
社会实践评语
2014/04/28 职场文书
歌颂祖国演讲稿
2014/05/04 职场文书
节约用水的口号
2014/06/20 职场文书
四风问题党员个人整改措施
2014/10/27 职场文书
建党伟业的观后感
2015/06/01 职场文书
校园新闻稿范文
2015/07/18 职场文书
《酸的和甜的》教学反思
2016/02/18 职场文书
Nginx使用X-Accel-Redirect实现静态文件下载的统计、鉴权、防盗链、限速等
2021/04/04 Servers
goland 清除所有的默认设置操作
2021/04/28 Golang