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 相关文章推荐
在Windows版的PHP中使用ADO
Oct 09 PHP
关于使用coreseek并为其做分页的介绍
Jun 21 PHP
学习php分页代码实例
Oct 24 PHP
Codeigniter的一些优秀特性总结
Jan 21 PHP
linux下实现定时执行php脚本
Feb 13 PHP
PHP实现恶意DDOS攻击避免带宽占用问题方法
May 27 PHP
PHP数组游标实现对数组的各种操作详解
Jan 26 PHP
PHP实现的简单sha1加密功能示例
Aug 27 PHP
PHP实现的日历功能示例
Sep 01 PHP
ThinkPHP框架整合微信支付之刷卡模式图文详解
Apr 10 PHP
laravel 如何实现引入自己的函数或类库
Oct 15 PHP
thinkphp5框架路由原理与用法详解
Feb 11 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
关于拼配咖啡,你要知道
2021/03/03 咖啡文化
php 时间计算问题小结
2009/01/04 PHP
php防攻击代码升级版
2010/12/29 PHP
PHP持久连接mysql_pconnect()函数使用介绍
2012/02/05 PHP
php利用scws实现mysql全文搜索功能的方法
2014/12/25 PHP
详解PHP的Yii框架中日志的相关配置及使用
2015/12/08 PHP
php array_keys 返回数组的键名
2016/10/25 PHP
[原创]php token使用与验证示例【测试可用】
2017/08/30 PHP
var与Javascript变量隐式声明
2009/09/17 Javascript
jquery实现按Enter键触发事件示例
2013/09/10 Javascript
js获取select标签的值且兼容IE与firefox
2013/12/30 Javascript
jquery实现对联广告的方法
2015/02/05 Javascript
javascript实现跨域的方法汇总
2015/06/25 Javascript
Vue.js基础知识汇总
2016/04/27 Javascript
node.js发送邮件email的方法详解
2017/01/06 Javascript
for循环 + setTimeout 结合一些示例(前端面试题)
2017/08/30 Javascript
基于匀速运动的实例讲解(侧边栏,淡入淡出)
2017/10/17 Javascript
深入理解Vue 单向数据流的原理
2017/11/09 Javascript
记React connect的几种写法(小结)
2018/09/18 Javascript
解决vue 界面在苹果手机上滑动点击事件等卡顿问题
2018/11/27 Javascript
基于redis的小程序登录实现方法流程分析
2020/05/25 Javascript
在vue中封装的弹窗组件使用队列模式实现方法
2020/07/23 Javascript
[02:49]2018DOTA2亚洲邀请赛主赛事决赛日战况回顾 Mineski鏖战5局夺得辉耀
2018/04/10 DOTA
Python logging模块学习笔记
2014/05/24 Python
win系统下为Python3.5安装flask-mongoengine 库
2016/12/20 Python
Python Socket实现简单TCP Server/client功能示例
2017/08/05 Python
python使用gdal对shp读取,新建和更新的实例
2020/03/10 Python
python如何对链表操作
2020/10/10 Python
HTML5语义化元素你真的用对了吗
2019/08/22 HTML / CSS
几个人围成一圈的问题
2013/09/26 面试题
销售部主管岗位职责
2013/12/18 职场文书
岗位廉政承诺书
2014/03/27 职场文书
《长江之歌》教学反思
2014/04/17 职场文书
先进工作者申报材料
2014/12/23 职场文书
教师师德表现自我评价
2015/03/05 职场文书
2015年民兵整组工作总结
2015/07/24 职场文书