《自动售货机仿真》实验报告 本文关键词:仿真,实验,售货机,报告
《自动售货机仿真》实验报告 本文简介:《自动售货机仿真》实验报告《自动售货机仿真》实验报告1、问题描述–①有一种自动售货机VM,可售三种商品:可乐(每听$0.25),咖啡(每听$0.30),餐巾纸(每包$0.05)。每种商品的示意图形下方都有一个按钮。一台VM中最多能够容纳NC听可乐、NF听咖啡、NT包餐巾纸。–②顾客使用VM购买商品时
《自动售货机仿真》实验报告 本文内容:
《自动售货机仿真》实验报告
《自动售货机仿真》实验报告
1、
问题描述
–
①
有一种自动售货机VM,可售三种商品:可乐(每听$0.25),咖啡(每听$0.30),餐巾纸(每包$0.05)。每种商品的示意图形下方都有一个按钮。一台VM中最多能够容纳NC听可乐、NF听咖啡、NT包餐巾纸。
–
②
顾客使用VM购买商品时,先从投币口投入硬币(共有三种硬币:$0.05;$0.10;$0.25),在投入的硬币总值达到或超过其欲购商品之价格后,再按下对应商品的按钮,VM即从出货口自动吐出一件商品,并从找币口找零。
–
③
如果顾客在其投入的硬币总值没有达到其欲购商品之价格时就按下了对应商品的按钮,或者最近一次投币30秒后既不继续投币,也不按下商品按钮,VM均从找币口吐出与该顾客已投入的硬币总值等值的硬币,但不吐出商品。
–
④
如果顾客欲购之商品已经售完,则在顾客按下该商品的按钮后,VM从找币口吐出与该顾客已投入的硬币总值等值的硬币。
–
⑤
当某种商品还剩NL听/包时,VM即自动发出短信,将VM的代号和缺货的商品名称通知管理人员。管理人员将在时间TM后收到短信,再用时间TS到达VM,并使VM的所有商品存货都达到最大容纳量,取走VM中的硬币,并留有找零的硬币:$0.05、$0.10、$0.25分别留C5、C10、C25枚。
须仿真的活动及开发结果的行为特征
–
1、开始仿真时,应随机产生VM中三种商品的存货量(不能超过其最大容纳量)和VM中三种硬币的数量(分别不小于C5、C10、C25枚)。
–
2、仿真中,应随机产生前来购物的顾客,随机产生其欲购买的商品种类,随机产生顾客的投币行为(包括③描述的行为),按问题域概述给出的要求进行VM自动售货活动的仿真。
–
3、NC、NF、NT、NL、C5、C10、C25的值应在运行仿真程序时用命令行给出,或者在开始仿真时从界面输入。
–
4、实时显示各种商品的当前存货量。
–
5、出现情况⑤时,应显示所发的短信内容,并随机决定TM和TS的值。在管理人员到达VM之前,应照常进行顾客购物的仿真。管理人员加货和取款的持续时间可忽略不计。
–
6、仿真开始后,应自动记销售流水帐。该流水帐的每一行对应着一次售货,记录着所售出的商品名称和售出时间。
–
7、仿真结束时,应自动产生销售报表。该报表应给出本次模拟过程中:每种商品的销售总量与价值合计;所有售出商品的价值总计;每种商品的库存量;模拟开始、结束时各自的库存金额;管理人员每次加货的时间、各商品加货量、取走的硬币总额。
2、
程序设计过程
1.
从实际问题中抽象类
仿真过程关注的事物有:VM,商品(Goods),顾客(Customer),管理员(Administrator)。
程序设计过程中考虑过以下问题:
1
管理员类建立的必要性。若不设计管理员类,而是在VM类中设两变量TS,TM,VM自动计时,到时间后自动加货,可实现同样输出。从程序外观上看管理员类的建立与否没有影响。而考虑到自动加货并不是VM的本身属性,而是通过与管理员通信完成的,故建立管理员类。在VM中建立响应管理员加货的方法,而管理员的内部实现也正是调用了VM的此方法。
2
商品基类建立的必要性。曾考虑过将Goods类设计为虚基类,提供所有商品的共有接口,再从这个虚基类派生处各具体商品,最后运用多态性原理设计实现细节。考虑到这个问题中各商品所不同的地方只是商品名,价格等数据成员不同,类内部方法完全相同。且此程序中一个Goods对象代表一组同种商品,即找不到一个个单独的商品。在电梯程序中每个乘客有不同的属性:起始与终止楼层,而这正是程序关系的特征,故建立了一个个具体的乘客对象。此问题中我们关系的只是商品的数量,故没有一个个单独的商品对象。
2.
三个类之间的关系
Goods
投币
按按钮
补充货物
发送请求
包含若干
出货
找零
Customer
VM
Administrator
3.
程序的主框架
初始化
结束
打印报表
(未达结束条件时循环)
检查是否需要新建顾客对象
检查是否需要通知管理员
顾客执行一次操作
VM执行一次操作
管理员执行一次操作
此程序中关键是要处理各对象之间的通信。采用以下方法解决:
1
VM与顾客之间的通信:顾客有两种操作,即投币与按按钮。在VM中建立响应这两种操作的函数,顾客类中的两种操作内部实质是调用VM中的响应函数。只需向顾客的操作函数中传递一VM的指针即可实现两者之间的通信。
2
VM与管理员的通信:因VM管理员之间的通信存在时间差,即VM发出的信息需经TM后才能传递到管理员,故①中方法不再适用。采用一全局变量(CallAdmTimeLeft)来记录信息还需多长时间才能到达管理员,其值为-1表示VM为发出请求或上一个请求已被处理,值为0则通知管理员。这样便可通过主函数完成消息的传递。
4.
类的设计
1)
“Pbulic,h“中声明定义了各类共享的一些数据类型及运行时需要的一些参数。
类型:
enum
Coin{FIVE=5,TEN=10,TWFIVE=25}:硬币的种类
typedef
unsigned
int
ID:VM编号的类型
typedef
int
PRICE:价格,现金的类型,单位为美分
typedef
int
TIME:时间的类型
运行时所需的参数,集中放置方便修改
const
int
COINKINDS:硬币种类数目
const
int
COINMAX:产生顾客时,其拥有的硬币数目的最大值
const
int
WAITTIME:顾客两次操作间最长时间间隔
const
int
CREATEMAX:一次交易结束后产生下一顾客的最大间隔时间
const
int
TMMAX:TM的最大值
const
int
TSMAX=5:TS的最大值
const
int
THEID:VM的编号
const
int
RUNTIME:运行的最大时间
2)
商品(Goods)类的设计
变量/函数
成员
作用
私有
string
name
标示商品名称
PRICE
price
标示商品价格
int
maxNum
售货机中该商品的最大容量
int
leftNum
记录售货机中该商品的剩余量
int
allSold
记录该商品的销售量
Goods(const
Goods&)
防止按值传递
const
Goods&
operator=(const
Goods&)
防止按值传递
公有
Goods(string,PRICE,int,int
)
构造函数
getName()
返回商品名称
getPrice()
返回商品价格
getLeftNum()
返回剩余数量
getAllSold()
返回销售量
setMax()
将商品数量冲至最大值
sellOne()
销售一件商品时应执行的操作
3)
顾客(Customer)类的设计
变量/函数
成员
作用
私有
string
goodsWanted
标示所需商品
vector
money
投币顺序,建立对象时初始化
PRICE
alreadyInsert
已投的金额,用于与商品价格比较,判断是否按按钮
PRICE
moneyLeft
记录当前剩余金额
int
timeleft
记录产生下一投币动作或按按钮动作还剩的时间
Customer(const
Customer&)
防止按值传递
const
Customer&
operator=(const
Customer&)
防止按值传递
setTimeLeft()
设置产生下一投币动作或按按钮动作还剩的时间
setMoneyLeft()
及时更新moneyLeft
公有
Customer(vector)
构造函数
insert(VM*)
处理投币行为
pressButton(VM*)
处理按按钮行为
oneSecondPast(VM*
)
程序每运行一秒顾客的更新,返回是否交易结束
Insert函数和pressButton函数的实现主要是调用VM的相应相应函数。
onSecondPast函数实现如下:
timeLeft>0?
返回true
返回false
Y
N
投币
按按钮
N
Y
钱没投完&&没有投够?
timeLeft为零?
Y
timeLeft--
4)
管理员(Administrator)类的设计
变量/函数
成员
作用
私有
TIME
timeLeft
到达VM剩余的时间,值为-1表示还未收到信息,空闲
VM*
pVM
目标VM
公有
Administrator()
构造函数
onCall(VM*
theVM)
收到请求时的操作
setMax()
为VM补充货物
oneSecondPast()
程序每运行一秒管理员的更新
5)VM类的设计
变量/函数
成员
作用
私有
ID
id
编号
vector
allGoods
商品容器
TIME
tradeTimeLeft
用于判断顾客是否在WAITTIME内无任何动作
bool
haveSend
标示是否已发送信息,防止重复发送
PRICE
tempPayment
记录当前顾客已投的金额
int
ensure
用于记录收支,从而判断售货机是否算错帐
vector
moneyContainer
当前VM的的硬币,三个分量分别存储三种硬币的数目
sendMessage(vector,bool&
)
发送缺货消息
examine(bool&)
检查是否需要通知管理员
VM(const
VM&)
防止按值传递
const
VM&
operator=(const
VM&)
防止按值传递
getMoneyLeft()
返回VM中剩余现金
caculate(int,vector&
)
计算找零,返回三种硬币各需找几枚
change(vector&)
找零
公有
VM()
默认构造函数
VM(ID.)
构造函数
getGoodsPrice(string)
根据商品名寻找其价格
onSetMax()
响应管理员的加货行为
onInsert(Coin)
响应顾客的投币行为
onPressButton(string,PRICE)
响应顾客的按按钮行为
StoragePrint(int)
打印存货量,向屏幕及输出文件输出
StoragePrint()
打印存货量,向报表输出
moneyPrint()
打印库存金额,向报表输出
workDayOver()
仿真结束时完成报表
oneSecondPast(bool&
)
程序每运行一秒VM的更新
onPressButton函数的实现:
按钮被按下
无此商品或此商品已售完?
Y
N
支付金额足够?
退还已投币
N
退还已投币
退还已投币
N
Y
售出商品,找零
Y
能够找零?
workDayOver中判断VM是否算错帐的实现:
通过ensure判断下式是否成立:
初始金额+售出货物价值-结束时剩余金额-管理员取走的==0
若成立,则没有算错帐。
3、
输入输出的设计
按要求,NL,C5,C10,C25从命令行给出。命令行最后一个函数若为Debugon,则使用文件输入商品名称,价格等信息,否则使用默认的信息。
输出有两个文件。“output.txt“中记录的内容与屏幕上显示的相同,记录了产生顾客的事件,顾客每一次投币、按按钮的事件,及每秒VM各商品的存货量,管理员加货的事件,VM发送的消息内容。“record.txt“中记录了每一次销售记录,管理员每次的加货时间、加货量、取走硬币的金额及仿真结束时产生的销售报表。
4、
图形用户界面的开发
1
设计界面。
2
对类做部分修改,尤其是输入输出修改。由于初学MFC,故在MFC版本中一些功能被省去,如从商品的种类价格在文件中设定暂时无法在MFC中实现。
3
用定时器触发程序的运行。
5、
参考书籍
《C++编程思想(第一卷)》Bruce
Eckel著。程序中“require.h“文件完全来自于该书,头文件中提供的函数功能类似于C中的assert宏。此程序中利用require寻找错误,主要在调试阶段使用。可用C++中的异常来改进使用require函数的地方,但异常尚未学习,故先用require函数。
《VC++深入详解》孙鑫、余安萍著。
《Visual
C++
6.0
开发指南》高手传等编著。图形用户界面的编写主要参考上述两本书。
6、
软件使用说明
开发环境:两版本均在Visual
C++
6.0下测试通过。
1)
Win32控制台版本:
VM文件夹下文件/文件夹:
Administrator.h,Administrator.cpp,Customer.h,Customer.cpp,Goods.h,
Goods.cpp,VM.h,VM.cpp,Public.h,require.h,Test.cpp(main函数位于Test.cpp中),VM.dsp,VM.dsw,data.txt(存储输入数据),ouput.txt(存储输出数据),record.txt(存储报表),Debug文件夹。
在VM工程中已设置了命令行参数:2
20
15
15
Debugon
输入文件中也给了一些数据,如需改动请按以下格式写入数据:商品名称(换行)商品价格(换行)VM此商品中最大储量(换行)仿真时此商品初始数目。请勿在文件末尾加一空行,否则运行程序时回得到错误提示并退出程序。
如需改变其他运行参数,如每运行一次休眠的时间、顾客两次操作间的最大间隔时间,请在“Public.h“中修改并重新编译。
2)
MFC版本:
myVm文件夹下文件/文件夹:
Administrator.h,Administrator.cpp,Customer.h,Customer.cpp,Goods.h,
Goods.cpp,VM.h,VM.cpp,Public.h,require.h,myVM.h,myVM.cpp,myVM.dsp,myVM.dsw,myVM.rc,myVMDlg.h,myVMDlg.cpp,Resource.h,StdAfx.cpp,StdAfx.h,ouput.txt(存储输出数据),record.txt(存储报表),Debug文件夹,res文件夹
运行时首先输入NL,C5,C10,C25的值,点“提交“再点“开始“即可开始仿真,点“停止“即产生报表,点“退出“即可退出程序。