PHP設(shè)計(jì)模式入門(mén)之狀態(tài)模式原理與實(shí)現(xiàn)方法分析
本文實(shí)例講述了PHP設(shè)計(jì)模式入門(mén)之狀態(tài)模式原理與實(shí)現(xiàn)方法。分享給大家供大家參考,具體如下:
想必大家都用過(guò)自動(dòng)售賣(mài)的自動(dòng)飲料機(jī)吧,塞入硬幣或紙幣,選擇想要的飲料,飲料就會(huì)在機(jī)器的下方滾出。大家有沒(méi)有相關(guān)如果用程序去寫(xiě)一個(gè)飲料機(jī)要怎么樣實(shí)現(xiàn)呢?
首先我們可以分享一下這部飲料機(jī)有幾種狀態(tài)
一、沒(méi)有錢(qián)的狀態(tài)
二、有錢(qián)的狀態(tài)
三、售出的狀態(tài)
四、銷(xiāo)售一空的狀態(tài)
好吧,知道了這些狀態(tài)之后我們開(kāi)始寫(xiě)代碼了!
JuiceMachine.php
<?php /** * 飲料機(jī) * @author ben * */ class JuiceMachine{ /** * 糖果機(jī)一共存在四種狀態(tài):沒(méi)錢(qián),有錢(qián),成功售出以及銷(xiāo)售一空 * * 沒(méi)錢(qián)的狀態(tài) * @var INT */ const NOMONEY = 0; /** * 有錢(qián)的狀態(tài) * @var INT */ const HASMONEY = 1; /** * 成功售出的狀態(tài) * @var INT */ const SOLD = 2; /** * 銷(xiāo)售一空的狀態(tài) * @var INT */ const SOLDOUT = 3; /** * 記錄糖果機(jī)當(dāng)前的狀態(tài),初始化狀態(tài)為售空 * @var INT */ private $_state = JuiceMachine::SOLDOUT; /** * 該變量用于記錄飲料機(jī)中飲料的數(shù)量 */ private $_count; /** * 構(gòu)造方法,最主要是用來(lái)初始化count和state屬性的 */ public function __construct($count){ $this->_count = $count; //當(dāng)飲料機(jī)中的飲料數(shù)量大于零時(shí),將飲料機(jī)的狀態(tài)重置為沒(méi)有錢(qián)的狀態(tài)。 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 />"; } } /** * 點(diǎn)擊飲料對(duì)應(yīng)的按鈕 */ public function clickButton(){ if($this->_state == JuiceMachine::HASMONEY ){ echo "you clicked, we are giving you a bottle of juice...<br />"; $this->_state = JuiceMachine::SOLD; //改變飲料機(jī)的狀態(tài)為售出模式 $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 />"; } } /** * 發(fā)放飲料 */ 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 />"; //飲料機(jī)中的飲料數(shù)量減一 $this->_count--; if($this->_count <= 0){ echo "opps, runing out of juice<br />"; //如果這時(shí)飲料機(jī)中沒(méi)有飲料了,將飲料機(jī)的狀態(tài)重置為銷(xiāo)售一空 $this->_state = JuiceMachine::SOLDOUT; }else{ //將飲料機(jī)的狀態(tài)重置為沒(méi)有錢(qián) $this->_state = JuiceMachine::NOMONEY; } }elseif($this->_state == JuiceMachine::SOLDOUT){ //其實(shí)這種情況不應(yīng)該出現(xiàn) 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();
運(yùn)行的結(jié)果是:
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
到目前為止我們的程序運(yùn)行良好,沒(méi)有出現(xiàn)什么問(wèn)題,但是從這些多重的if判斷中你是否嗅到了壞代碼的味道呢?有一天問(wèn)題終于出現(xiàn)了,老板希望當(dāng)用戶(hù)點(diǎn)擊按鈕時(shí)有10%的概率拿到兩瓶飲料,我們需要為飲料機(jī)多加一個(gè)狀態(tài),這時(shí)去修改代碼就成為了一種災(zāi)難,而且很可能會(huì)影響到之前的代碼,帶來(lái)新的bug,看看狀態(tài)模式如何幫助我們度過(guò)難關(guān)吧!
狀態(tài)模式的官方定義是:狀態(tài)模式允許對(duì)象在內(nèi)部狀態(tài)改變是改變它的行為,對(duì)象看起來(lái)好像是修改了它的類(lèi)
用uml類(lèi)圖表示如下:
在我們這個(gè)項(xiàng)目中的實(shí)際類(lèi)圖如下:
具體實(shí)現(xiàn)代碼:
State.php
<?php interface State{ /** * 插入硬幣 */ public function insertCoin(); /** * 回退硬幣 */ public function retreatCoin(); /** * 點(diǎn)擊按鈕 */ public function clickButton(); /** * 發(fā)放飲料 */ public function dispend(); }
NomoneyState.php
<?php require_once 'State.php'; class NomoneyState implements State{ /** * 飲料機(jī)的實(shí)例 * * @var object */ private $_juiceMachine; /** * 構(gòu)造方法,主要用于初始化飲料機(jī)實(shí)例 * */ 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 />"; //將飲料機(jī)的狀態(tài)切換成有錢(qián)的狀態(tài) $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 { /** * 飲料機(jī)的實(shí)例 * * @var object */ private $_juiceMachine; /** * 構(gòu)造方法,主要用于初始化飲料機(jī)實(shí)例 */ 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 />"; // 改變飲料機(jī)的狀態(tài)為售出模式 $rand = mt_rand(0, 0); // 當(dāng)隨機(jī)數(shù)為0(即1/10的概率)并且飲料機(jī)中還有1瓶以上的飲料時(shí) 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{ /** * 飲料機(jī)的實(shí)例 * * @var object */ private $_juiceMachine; /** * 構(gòu)造方法,主要用于初始化飲料機(jī)實(shí)例 * */ 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{ /** * 飲料機(jī)的實(shí)例 * * @var object */ private $_juiceMachine; /** * 構(gòu)造方法,主要用于初始化飲料機(jī)實(shí)例 * */ 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 />"; //如果這時(shí)飲料機(jī)中沒(méi)有飲料了,將飲料機(jī)的狀態(tài)重置為銷(xiāo)售一空 $this->_juiceMachine->setState($this->_juiceMachine->getSoldoutState()); }else{ //將飲料機(jī)的狀態(tài)重置為沒(méi)有錢(qián) $this->_juiceMachine->setState($this->_juiceMachine->getNomoneyState()); } } }
WinnerState.php
<?php require_once 'State.php'; class WinnerState implements State { /** * 飲料機(jī)的實(shí)例 * * @var object */ private $_juiceMachine; /** * 構(gòu)造方法,主要用于初始化飲料機(jī)實(shí)例 */ 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 />"; // 如果這時(shí)飲料機(jī)中沒(méi)有飲料了,將飲料機(jī)的狀態(tài)重置為銷(xiāo)售一空 $this->_juiceMachine->setState($this->_juiceMachine->getSoldoutState()); } else { // 將飲料機(jī)的狀態(tài)重置為沒(méi)有錢(qián) $this->_juiceMachine->setState($this->_juiceMachine->getSoldoutState()); } } else { echo "opps, runing out of juice<br />"; // 如果這時(shí)飲料機(jī)中沒(méi)有飲料了,將飲料機(jī)的狀態(tài)重置為銷(xiāo)售一空 $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 { /** * 記錄糖果機(jī)當(dāng)前的狀態(tài),初始化狀態(tài)為售空 * * @var object */ private $_state; /** * 該變量用于記錄飲料機(jī)中飲料的數(shù)量 */ private $_count; /** * 構(gòu)造方法,最主要是用來(lái)初始化count和state屬性的 */ public function __construct($count) { $this->_state = new SoldoutState($this); $this->_count = $count; // 當(dāng)飲料機(jī)中的飲料數(shù)量大于零時(shí),將飲料機(jī)的狀態(tài)重置為沒(méi)有錢(qián)的狀態(tài)。 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(); //其實(shí)發(fā)放糖果是在用戶(hù)點(diǎn)擊完按鈕后機(jī)器內(nèi)部進(jìn)行的所有沒(méi)有必要再寫(xiě)一個(gè)dispend方法 $this->_state->dispend(); } /** * 設(shè)置糖果機(jī)的狀態(tài) * * @param State $state */ public function setState(State $state) { $this->_state = $state; } /** * 獲取沒(méi)有錢(qián)的狀態(tài) */ public function getNomoneyState(){ return new NomoneyState($this); } /** * 獲取有錢(qián)的狀態(tài) */ public function getHasmoneyState(){ return new HasmoneyState($this); } /** * 獲取售出的狀態(tài) */ public function getSoldState(){ return new SoldState($this); } /** * 獲取銷(xiāo)售一空的狀態(tài) */ public function getSoldoutState(){ return new SoldoutState($this); } /** * 獲取幸運(yùn)者的狀態(tài) */ public function getWinnerState(){ return new WinnerState($this); } /** * 獲取飲料機(jī)中飲料的數(shù)量 */ public function getCount(){ return $this->_count; } /** * 將飲料數(shù)量減一 */ public function decJuice(){ echo "now you get you juice<br />"; //飲料機(jī)中的飲料數(shù)量減一 $this->_count--; } }
index.php
<?php require_once 'JuiceMachine.php'; $juiceMachine = new JuiceMachine(2); $juiceMachine->insertCoin(); $juiceMachine->clickButton();
更多關(guān)于PHP相關(guān)內(nèi)容感興趣的讀者可查看本站專(zhuān)題:《php面向?qū)ο蟪绦蛟O(shè)計(jì)入門(mén)教程》、《PHP數(shù)組(Array)操作技巧大全》、《PHP基本語(yǔ)法入門(mén)教程》、《PHP運(yùn)算與運(yùn)算符用法總結(jié)》、《php字符串(string)用法總結(jié)》、《php+mysql數(shù)據(jù)庫(kù)操作入門(mén)教程》及《php常見(jiàn)數(shù)據(jù)庫(kù)操作技巧匯總》
希望本文所述對(duì)大家PHP程序設(shè)計(jì)有所幫助。
- PHP設(shè)計(jì)模式之原型模式示例詳解
- PHP設(shè)計(jì)模式之命令模式示例詳解
- PHP設(shè)計(jì)模式(四)原型模式Prototype實(shí)例詳解【創(chuàng)建型】
- PHP設(shè)計(jì)模式(三)建造者模式Builder實(shí)例詳解【創(chuàng)建型】
- PHP設(shè)計(jì)模式(一)工廠模式Factory實(shí)例詳解【創(chuàng)建型】
- PHP設(shè)計(jì)模式概論【概念、分類(lèi)、原則等】
- PHP設(shè)計(jì)模式之 策略模式Strategy詳解【對(duì)象行為型】
- PHP設(shè)計(jì)模式入門(mén)之迭代器模式原理與實(shí)現(xiàn)方法分析
- PHP設(shè)計(jì)模式之迭代器模式Iterator實(shí)例分析【對(duì)象行為型】
- php設(shè)計(jì)模式之適配器模式實(shí)例分析【星際爭(zhēng)霸游戲案例】
- php設(shè)計(jì)模式之迭代器模式實(shí)例分析【星際爭(zhēng)霸游戲案例】
- 詳解PHP八大設(shè)計(jì)模式
相關(guān)文章
PHP局部異常因子算法-Local Outlier Factor(LOF)算法的具體實(shí)現(xiàn)解析
這篇文章主要介紹了PHP局部異常因子算法-Local Outlier Factor(LOF)算法的具體實(shí)現(xiàn)解析,本文通過(guò)案例和文字解析一步步解釋了該項(xiàng)技術(shù)的實(shí)現(xiàn),以下就是詳細(xì)內(nèi)容,需要的朋友可以參考下2021-07-07PHP實(shí)現(xiàn)簡(jiǎn)單注冊(cè)登錄詳細(xì)代碼
這篇文章主要介紹了PHP實(shí)現(xiàn)簡(jiǎn)單注冊(cè)登錄詳細(xì)全部代碼實(shí)例講解,代碼講解的很清楚,對(duì)這方面不懂的初學(xué)者可以照著練習(xí)研究下2021-01-01destoon利用Rewrite規(guī)則設(shè)置網(wǎng)站安全
這篇文章主要介紹了destoon利用Rewrite規(guī)則設(shè)置網(wǎng)站安全,需要的朋友可以參考下2014-06-06Symfony2之session與cookie用法小結(jié)
這篇文章主要介紹了Symfony2之session與cookie用法,結(jié)合實(shí)例形式總結(jié)分析了Symfony框架針對(duì)session與cookie的設(shè)置、獲取及刪除等操作的實(shí)現(xiàn)方法,需要的朋友可以參考下2016-03-03寶塔 php修改了php.ini配置不生效的問(wèn)題及解決方法
最近在使用hypref,php的版本是7.4,服務(wù)器linux,用寶塔安裝完php,并裝完swoole插件后,安裝了swoole后,需要在php.ini中修改一下配置文件,本文給大家分享寶塔 php修改了php.ini配置不生效的問(wèn)題及解決方法,感興趣的朋友一起看看吧2023-09-09Laravel 關(guān)聯(lián)模型-關(guān)聯(lián)新增和關(guān)聯(lián)更新的方法
今天小編就為大家分享一篇Laravel 關(guān)聯(lián)模型-關(guān)聯(lián)新增和關(guān)聯(lián)更新的方法,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2019-10-10C/S和B/S兩種架構(gòu)區(qū)別與優(yōu)缺點(diǎn)分析
C/S和B/S,是再普通不過(guò)的兩種軟件架構(gòu)方式,都可以進(jìn)行同樣的業(yè)務(wù)處理,甚至也可以用相同的方式實(shí)現(xiàn)共同的邏輯。既然如此,為何還要區(qū)分彼此呢?那我們就來(lái)看看二者的區(qū)別和聯(lián)系。2014-10-10