免费、绿色、专业的手机游戏中心下载安装平台-游家吧

当前位置: 首页 > 教程攻略 > <<Head First设计模式>>之状态模式学习篇

<<Head First设计模式>>之状态模式学习篇

更新时间:2026-02-07 12:57:20

宝可梦咖啡厅最新版
  • 类型:模拟经营
  • 大小:
  • 语言:简体中文
  • 评分:
查看详情

<<Head First设计模式>>之状态模式学习篇

最近闲来无事翻阅了另一本书,感觉有些有趣,它涉及了OO的设计思想和原则。这本书是用#%#$#%@%@%$#%$#%#%#$%@_e++言来描述的,因为我比较熟悉C++,所以看完之后决定将这本书中的状态模式和工厂模式结合起来,在Windows计算器上进行一些编程实践。在阅读了书中关于糖果机的状态模式的例子后,我进行了深入的探讨,并尝试用C++编写了一个版本,这不仅加深了我的理解,还为我的编程技能增添了一些新的体验。如果你认为我在这篇文章中有任何地方写的不准确或者有其他改进建议,欢迎你提出你的见解。我们都可以从中学习和成长。毕竟,作为一个设计模式初学者,我的经验还不足,希望能够通过这次交流来提升自己。

下面是>一书中糖果机的状态图及相应的Java代码和C++实现代码:

糖果机共有状态:没有钱、有钱、售出糖果、糖果售罄、赢家状态。在以下状态图中,通过椭圆形来表示各个状态,并用箭头来显示从一种状态到另一种状态的转换。

我使用Visio作的糖果机状态图质量一般,尽管不太标准,但对理解UML中的状态模式很关键。继续深入状态模式的学习吧!

对应的Java代码如下:代码语言:javascript代码运行次数:0

运行

复制

```java import State.GumballMachine; import State.GumballMachineTestDrive;public class Main { public static void main(String[] args) { GumballMachine gumballMachine = new GumballMachine(; System.out.println(gumballMachine); System.out.println(The current gumball number is: + gumballMachine.getCount); gumballMachine.insertQuarter; gumballMachine.turnCrank; System.out.println(gumballMachine); System.out.println(The current gumball number is: + gumballMachine.getCount); gumballMachine.insertQuarter; gumballMachine.turnCrank; System.out.println(gumballMachine); System.out.println(The current gumball number is: + gumballMachine.getCount); gumballMachine.insertQuarter; gumballMachine.turnCrank; } } ```在这个代码示例中,我们创建了一个糖果机(`GumballMachine`)并使用了其测试驱动程序(`GumballMachineTestDrive`)。这个测试驱动程序将糖果机的初始化、添加硬币和转动把手的行为打印到控制台。这可以帮助你更好地理解和调试你的糖果机类实现。

运行结果截图如下: >之状态模式学习篇">

对应的C++代码如下:代码语言:javascript代码运行次数:0

运行

复制

<pre class="brush:php;toolbar:false;">//State抽象基类//State.h#pragma onceclass State{public:State(void);public:~State(void);public:// 投入25分钱virtual void insertQuarter(void)=0;public:// 退回25分钱virtual void ejectQuarter(void)=0;public:// 转动曲柄virtual void turnCrank(void)=0;public:// 发放糖果virtual void dispense(void)=0;};//State.cpp#include "State.h"State::State(void){}State::~State(void){}//没有25分钱状态类 NoQuarterState//NoQuarterState.h#pragma once#include "state.h"#include "GumballMachine.h"class NoQuarterState :public State{public:NoQuarterState(GumballMachine *pGumballMachine);public:~NoQuarterState(void);public:// 投入25分钱void insertQuarter(void);public:// 退回25分钱void ejectQuarter(void);public:// 转动曲柄void turnCrank(void);public:// 发放糖果void dispense(void);private:// 糖果机实例变量GumballMachine *m_pGumballMachine;};//NoQuarterState.cpp#include "NoQuarterState.h"#include <iostream>using namespace std;NoQuarterState::NoQuarterState(GumballMachine *pGumballMachine){this->m_pGumballMachine = pGumballMachine;}NoQuarterState::~NoQuarterState(void){}// 投入25分钱void NoQuarterState::insertQuarter(void){cout<<"You inserted a quarter"<<endl;m_pGumballMachine->setState(m_pGumballMachine->getHasQuarterState());}// 退回25分钱void NoQuarterState::ejectQuarter(void){cout<<"You haven't inserted a quarter"<<endl;}// 转动曲柄void NoQuarterState::turnCrank(void){cout<<"You turned, but there's no quarter"<<endl;}// 发放糖果void NoQuarterState::dispense(void){cout<<"You need to pay first"<<endl;}//有25分钱状态 HasQuarterState//HasQuarterState.h#pragma once#include "state.h"#include "GumballMachine.h"class HasQuarterState :public State{public:HasQuarterState(GumballMachine *pGumballMachine);public:~HasQuarterState(void);public:// 投入25分钱void insertQuarter(void);public:// 退回25分钱void ejectQuarter(void);public:// 转动曲柄void turnCrank(void);public:// 发放糖果void dispense(void);private:// 糖果机实例变量GumballMachine *m_pGumballMachine;};//HasQuarterState.cpp#include "HasQuarterState.h"#include <iostream>#include <cstdlib>#include <ctime>using namespace std;HasQuarterState::HasQuarterState(GumballMachine *pGumballMachine){this->m_pGumballMachine = pGumballMachine;}HasQuarterState::~HasQuarterState(void){}// 投入25分钱void HasQuarterState::insertQuarter(void){cout<<"You can't insert another quarter"<<endl;}// 退回25分钱void HasQuarterState::ejectQuarter(void){cout<<"Quarter returned"<<endl;m_pGumballMachine->setState(m_pGumballMachine->getNoQuarterState());}// 转动曲柄void HasQuarterState::turnCrank(void){cout<<"You turned..."<<endl;// srand(time(0)); //用时间作种子,使每次随即的数字不一样//int winner = (int)(10.0*rand()/(RAND_MAX+1.0)); // 产生随机数int winner = rand()%10; // 产生随机数cout<<winner<<endl;if((winner == 3) && (m_pGumballMachine->getCount()>1)){ m_pGumballMachine->setState(m_pGumballMachine->getWinnerState());}else{m_pGumballMachine->setState(m_pGumballMachine->getSoldState());}}// 发放糖果void HasQuarterState::dispense(void){cout<<"No gumball dispensed"<<endl;}//售出糖果状态 SoldState//SoldState.h#pragma once#include "state.h"#include "GumballMachine.h"class SoldState :public State{public:SoldState(GumballMachine *pGumballMachine);public:~SoldState(void);public:// 投入25分钱void insertQuarter(void);// 退回25分钱void ejectQuarter(void);// 转动曲柄void turnCrank(void);// 发放糖果void dispense(void);private:// 糖果机实例变量GumballMachine *m_pGumballMachine;};//SoldState.cpp#include "SoldState.h"#include <iostream>using namespace std;SoldState::SoldState(GumballMachine *pGumballMachine){this->m_pGumballMachine = pGumballMachine;}SoldState::~SoldState(void){}// 投入25分钱void SoldState::insertQuarter(void){cout<<"Please wait, we're already giving you a gumball"<<endl;}// 退回25分钱void SoldState::ejectQuarter(void){ cout<<"Sorry, you already turned the Crank"<<endl;}// 转动曲柄void SoldState::turnCrank(void){cout<<"Turning twice doesn't get you another gumball!"<<endl;}// 发放糖果void SoldState::dispense(void){m_pGumballMachine->releaseBall();if(m_pGumballMachine->getCount()>0){m_pGumballMachine->setState(m_pGumballMachine->getNoQuarterState());}else{cout<<"Oops, out of gumballs!"<<endl;m_pGumballMachine->setState(m_pGumballMachine->getSoldOutState());}}//糖果售罄状态 SoldOutState类//SoldOutState.h#pragma once#include "state.h"#include "GumballMachine.h"class SoldOutState :public State{public:SoldOutState(GumballMachine *pGumballMachine);public:~SoldOutState(void);public:// 投入25分钱void insertQuarter(void);// 退回25分钱void ejectQuarter(void);// 转动曲柄void turnCrank(void);// 发放糖果void dispense(void);private:// 糖果机实例变量GumballMachine *m_pGumballMachine;};//SoldOutState.cpp#include "SoldOutState.h"#include <iostream>using namespace std;SoldOutState::SoldOutState(GumballMachine *pGumballMachine){this->m_pGumballMachine = pGumballMachine;}SoldOutState::~SoldOutState(void){}// 投入25分钱void SoldOutState::insertQuarter(void){cout<<"You can't insert a quarter, the machine is sold out"<<endl;}// 退回25分钱void SoldOutState::ejectQuarter(void){cout<<"You can't eject, you haven't inserted a quarter yet"<<endl;}// 转动曲柄void SoldOutState::turnCrank(void){cout<<"You turned, but there are no gumballs"<<endl;}// 发放糖果void SoldOutState::dispense(void){cout<<"No gumball dispensed"<<endl;}//赢家状态 WinnerState类//WinnerState.h#pragma once#include "state.h"#include "GumballMachine.h"class WinnerState :public State{public:WinnerState(GumballMachine *pGumballMachine);public:~WinnerState(void);public:// 投入25分钱void insertQuarter(void);public:// 退回25分钱void ejectQuarter(void);public:// 转动曲柄void turnCrank(void);public:// 发放糖果void dispense(void);private:// 糖果机实例变量GumballMachine *m_pGumballMachine;};//WinnerState.cpp#include "WinnerState.h"#include <iostream>using namespace std;WinnerState::WinnerState(GumballMachine *pGumballMachine){this->m_pGumballMachine = pGumballMachine;}WinnerState::~WinnerState(void){}// 投入25分钱void WinnerState::insertQuarter(void){cout<<"Please wait, we're already giving you a gumball"<<endl;}// 退回25分钱void WinnerState::ejectQuarter(void){cout<<"Sorry, you already turned the Crank"<<endl;}// 转动曲柄void WinnerState::turnCrank(void){cout<<"Turning twice doesn't get you another gumball!"<<endl;}// 发放糖果void WinnerState::dispense(void){cout<<"You're a Winner! You get two gumballs for your quarter";m_pGumballMachine->releaseBall();if(m_pGumballMachine->getCount() == 0){ m_pGumballMachine->setState(m_pGumballMachine->getSoldOutState());}else{ m_pGumballMachine->releaseBall(); if(m_pGumballMachine->getCount()>0){ m_pGumballMachine->setState(m_pGumballMachine->getNoQuarterState()); }else{ cout<<"Oops, out of gumballs!"<<endl; m_pGumballMachine->setState(m_pGumballMachine->getSoldOutState()); }}}//糖果机 上下文环境GumballMachine类//GumballMachine.h#pragma once#include "State.h"class GumballMachine{public:GumballMachine(int numberGumballs=0);public:~GumballMachine(void);private:// 状态类的指针State* m_pState;private:// 记录机器内的糖果数目int m_count;State* m_pSoldOutState;State* m_pNoQuarterState;State* m_pHasQuarterState;State* m_pSoldState;State* m_pWinnerState;public:void insertQuarter(void);public:// 退回25分钱void ejectQuarter(void);public:// 转动曲柄void turnCrank(void);public:// 设置状态void setState(State* pState);public:// 释放糖果void releaseBall(void);public:// 获取当前糖果的数目int getCount(void);// 获取发放糖果状态State* getSoldState(void);// 获取拥有25分钱状态State* getHasQuarterState(void);// 获取没有25分钱状态State* getNoQuarterState(void);// 获取糖果售罄状态State* getSoldOutState(void);public:// 获取赢家状态State* getWinnerState(void);};//GumballMachine.cpp#include "GumballMachine.h"#include "NoQuarterState.h"#include "HasQuarterState.h"#include "SoldOutState.h"#include "SoldState.h"#include "WinnerState.h"#include <iostream>using namespace std;GumballMachine::GumballMachine(int numberGumballs){m_pSoldOutState = new SoldOutState(this);m_pNoQuarterState = new NoQuarterState(this);m_pHasQuarterState = new HasQuarterState(this);m_pSoldState = new SoldState(this);this->m_count = numberGumballs;m_pState = m_pSoldOutState;if(numberGumballs>0){m_pState = m_pNoQuarterState;}}GumballMachine::~GumballMachine(void){ delete m_pSoldOutState; delete m_pNoQuarterState;delete m_pHasQuarterState;delete m_pSoldState;}void GumballMachine::insertQuarter(void){ m_pState->insertQuarter();}// 退回25分钱void GumballMachine::ejectQuarter(void){m_pState->ejectQuarter();}// 转动曲柄void GumballMachine::turnCrank(void){m_pState->turnCrank();m_pState->dispense();}// 设置状态void GumballMachine::setState(State* pState){this->m_pState = pState;}// 释放糖果void GumballMachine::releaseBall(void){cout<<"A gumball comes rolling out of the solt...";if(m_count != 0){m_count = m_count -1;}}// 获取当前糖果的数目int GumballMachine::getCount(void){return m_count;}// 获取发放糖果状态State* GumballMachine::getSoldState(void){return m_pSoldState;}// 获取拥有25分钱状态State* GumballMachine::getHasQuarterState(void){ return m_pHasQuarterState;}// 获取没有25分钱状态State* GumballMachine::getNoQuarterState(void){return m_pNoQuarterState;}// 获取糖果售罄状态State* GumballMachine::getSoldOutState(void){return m_pSoldOutState;}// 获取赢家状态State* GumballMachine::getWinnerState(void){return m_pWinnerState;}//测试主函数文件 TestDriver.cpp#include "GumballMachine.h"#include <iostream>using namespace std;int main(){ srand(time(NULL)); //以系统时间作为种子,设置随机数种子登录后复制代码语言:javascript代码运行次数:0

运行

复制

<pre class="brush:php;toolbar:false;"> GumballMachine *pGumballMachine = new GumballMachine(5);pGumballMachine->insertQuarter();pGumballMachine->turnCrank();cout<<"the gumball count is:"<<pGumballMachine->getCount()<<endl;pGumballMachine->insertQuarter();pGumballMachine->turnCrank();cout<<"the gumball count is:"<<pGumballMachine->getCount()<<endl;pGumballMachine->insertQuarter();pGumballMachine->turnCrank();cout<<"the gumball count is:"<<pGumballMachine->getCount()<<endl;pGumballMachine->insertQuarter();pGumballMachine->turnCrank();cout<<"the gumball count is:"<<pGumballMachine->getCount()<<endl;pGumballMachine->insertQuarter();pGumballMachine->turnCrank();cout<<"the gumball count is:"<<pGumballMachine->getCount()<<endl;pGumballMachine->insertQuarter();pGumballMachine->turnCrank();cout<<"the gumball count is:"<<pGumballMachine->getCount()<<endl;pGumballMachine->insertQuarter();pGumballMachine->turnCrank();cout<<"the gumball count is:"<<pGumballMachine->getCount()<<endl;return 0;}登录后复制

下面是程序运行结果截图: >之状态模式学习篇">

在校园里体验状态模式你是否还记得以前在学校学习Java时做的实验报告?那里有一个关于地铁十字旋转门(turnstile)的状态模式练习。在我看来,这个例子非常容易理解。它来源于日常生活中的实际应用,让我们有机会从不同角度审视和思考问题。当我们进入一个房间时,它可能会根据我们选择的类型自动调整到不同的状态。例如,如果我们在一个咖啡馆里,它可能是一个安静的环境,当音乐开始时会变得嘈杂。这种变化是通过观察当前的状态来决定的。这个过程展示了如何使用状态模式来处理对象在不同状态下的行为。当你尝试理解并实现这样的系统,你将会发现这是一个非常实用和灵活的方法论。它有助于我们设计出更加健壮和响应良好的应用程序。

在地铁十字旋转门(turnstile)的操作中,存在一个简单的有限状态机(FSM)。它管理着乘客前往列车站台的大门。下图展示了地铁十字转门的初步状态机。--- 状态模式学习篇# 代码语言: - JavaScript# 运行次数: 0

运行

复制

状态图由四个关键部分构成。它包含矩形框代表的状态,箭头指示状态转换,而箭头上方的两个元素分别标记事件和响应动作。对于使用JavaScript进行编程的程序员而言,当访问此段代码时,JavaScript运行次数为零。这确保了您的程序在初次加载时不会执行任何不必要的操作。

运行

复制

<pre class="brush:php;toolbar:false;">( 若状态机处于锁(Locked)状态,接收到投币(coin)事件,则执行解锁(Unlock)操作,并转入开放状态(Unlocked)。登录后可复制以下代码示例:javascript运行次数:0

运行

复制

( 当状态机处于锁定(Locked)模式时,接收到“通过”(Pass)信号则启动报警操作,但不会进行状态转换。示例代码如下: ```javascript function handlePassEvent { alarm; } ``` 执行后,JavaScript运行次数为:

运行

复制

若状态机处于Unlocked(开启)模式,接收到pass(通行信号)时执行lock操作,随后进入Locked(锁定)状态。此过程涉及JavaScript代码运行计数为。

运行

复制

<pre class="brush:php;toolbar:false;">(若状态机处于Unlocked(开启)状态,接收到coin(投币)事件,则执行refund(退款)操作;无需状态转换。登录后可复制以下代码段:
<javascript>
    var codeRunCount =
</javascript>

运行

复制

<pre class="brush:php;toolbar:false;">我们用一般的方法描述这件事应该是这样:登录后复制代码语言:javascript代码运行次数:0

运行

复制

用TurnstileController封装旋转门操作,实现开门、报警和关门功能,并跟踪事件状态。当新的事件发生时,根据当前状态调用对应的处理方法。例如,当有硬币通过时解锁门并记录。

但是这种实现方式至少有以下两个问题:

1)当状态数目不是很多的时候,Switch/Case可能可以搞定。但是当状态数目很多的时候(实际系统中也正是如此),维护一大组的Switch/Case语句将是一件异常困难并且容易出错的事情。

2)状态逻辑和动作实现没有分离。在很多的系统实现中,动作的实现代码直接写在状态的逻辑当中。这带来的后果就是系统的扩展性和维护得不到保证。

接下来是关于State模式的介绍:在State模式下,我们将状态逻辑和动作实现相分离。当一个操作需要维护复杂的case分支语句,并且这些分支依赖于对象的状态时,可以使用State模式将每个分支封装到独立的类中。典型的类图结构如下:

在编程中,通过抽象出一个通用的状态接口来封装所有可能的状态变化,使得不同状态间的转换更加灵活和高效。

Context(上下文)拥有一个当前的内部状态

不管什么时候发生一个事件(someEventHappen),Context将委托给具体的状态类去处理

具体状态,处理Context的请求,每一个具体状态实现了在该状态下,针对某一事件的特定响应动作和下一步的状态迁移 >之状态模式学习篇">

上面这幅图来源于>的状态模式章节。代码语言:javascript代码运行次数:0

运行

复制

<pre class="brush:php;toolbar:false;">代码如下:登录后复制代码语言:javascript代码运行次数:0

运行

复制

<pre class="brush:php;toolbar:false;">interface State{public void someEventHappen(Context c);}class StateA implements State{public void someEventHappen(Context c){c.actionA();c.state = new StateB();}}class StateB implements State{public void someEventHappen(Context c){c.actionB();c.state = new StateA();}}class Context{public State state = new StateA();public void someEventHappen(){state.someEventHappen(this);}public void actionA(){System.out.println("action A is going on...");}public void actionB(){System.out.println("aciton B is going on...");}}public class StateTest{public static void main(String [] args){Context c = new Context();c.someEventHappen();c.someEventHappen();}}登录后复制代码语言:javascript代码运行次数:0

运行

复制

<pre class="brush:php;toolbar:false;">注意该代码实现了如下的状态机:登录后复制>之状态模式学习篇">代码语言:javascript代码运行次数:0

运行

复制

<pre class="brush:php;toolbar:false;">你的任务:登录后复制代码语言:javascript代码运行次数:0

运行

复制

明白了,下面是我为你编写的代码:```php class Treadmill { public $status = 'stopped'; public function turnstileStatus($newStatus) { switch ($this->status) { case 'stopped': if ($newStatus == 'running') { $this->status = 'running'; } break; case 'running': if ($newStatus == 'stopped') { $this->status = 'stopped'; } break; } echo 当前自动扶梯状态为: . $this->status . \n; } }$treadmill = new Treadmill; $treadmill->turnstileStatus('running'); // 假设这是一个运行按钮,可以切换到停止或开始状态// 现在状态为:自动扶梯正在运行 ```这段代码模拟了地铁十字旋转门的逻辑,并通过状态模式来实现其功能。

下面是我的Java实现代码,不知道对不对。代码语言:javascript代码运行次数:0

运行

复制

<pre class="brush:php;toolbar:false;">//MyTurstileTest.javainterface State{public abstract void DropCoinEventHappen(Context c); public abstract void PassEventHappen(Context c);}class Context { private State state = new LockedState(); public void CoinEventHappen(){ state.DropCoinEventHappen(this); } public void PassEventHappen(){ state.PassEventHappen(this); } public void unlock(){System.out.println("正在执行开门操作.......");state = new UnLockedState(); }public void alarm(){System.out.println("注意! 有人强行越过旋转门.......");state = new LockedState();}public void lock(){System.out.println("正在执行关门操作........");state = new LockedState(); }public void refund(){System.out.println("退款中........"); state = new UnLockedState();} }class LockedState implements State{public void DropCoinEventHappen(Context c){ c.unlock();//执行开门操作} public void PassEventHappen(Context c){c.alarm();//报警 }}class UnLockedState implements State{public void DropCoinEventHappen(Context c){ c.refund();//退款}public void PassEventHappen(Context c){c.lock();//执行关门操作}}public class MyTurstileTest{public static void main(String[] args){Context c = new Context();System.out.println("地铁十字旋转门初始态为关的状态......");//起始状态地铁十字旋转门(turnstile)默认处于关的状态c.CoinEventHappen();//turnstile状态为关时,发生投币操作,事件发生后turnstile状态为开c.PassEventHappen();//turnstile状态为开时,发生人员通过事件,事件发生后turnstile状态为关c.PassEventHappen();//turnstile状态为关时,发生人员通过事件,事件发生后turnstile状态为开c.CoinEventHappen();//turstile状态为关时,发生投币操作,事件发生后turnstile状态为开}}登录后复制

下面是程序运行代码运行结果的贴图 >之状态模式学习篇">

除此之外,我还计划使用MFC结合状态模式和工厂模式开发一个标准版的Windows计算器应用程序。该程序将包括五个主要的状态:左操作数、操作符、右操作数、结果及错误状态。为了确保代码的清晰性和可维护性,我还会考虑区分单目运算符和双目运算符。完成这个练习后,我会整理出关键的状态图以及与C++相关的类设计代码,并上传以进行状态模式的学习总结。

以上就是<<Head First设计模式>>之状态模式学习篇的详细内容,更多请关注其它相关文章!

精品推荐

相关文章

最新资讯

热门文章

更多

最新推荐

更多

最新更新

更多