(5)每位乘客初次所要到达的楼层是随机的,令其在合适的电梯处等待电梯到来。
(6)每位乘客乘坐合适的电梯到达指定楼层后,随机地停留10-120秒后,再随机地去往另一楼层,依此类推,当每人乘坐过L次(每人的L值不同,在产生乘客时随机地在1~10次之间确定)电梯后,第L+1次为下至底层并结束乘梯行为。
到所有乘客结束乘梯行为时,本次仿真结束。
(7)电梯运行速度为S秒/层(S值可以根据仿真情况在1~5之间确定),每人上下时间为T秒(T值可以根据仿真情况在2~10之间确定)。
(8)电梯运行的方向由先发出请求者决定,不允许后发出请求者改变电梯的当前运行方向,除非是未被请求的空梯。
(9)当某层有乘客按下乘梯电钮时,优先考虑离该层最近的、满足条件(8)、能够最快到达目标层的电梯。
(10)不允许电梯超员。
3.开发结果的行为特征
(1)产生事件的周期为1秒,每次可产生0个或多个事件。
(2)各随机事件由互不相关的伪随机数发生器决定。
(3)设计一个易于理解的界面,动态显示各梯的载客与运行情况,动态显示各楼层的人员停留情况与要求乘梯情况;动态显示从仿真开始到目前的时间。
(4)显示时用应表示出不同的乘客及其当前所要求去往的楼层。
例如,12-32表示标识为12的乘客要求去往32层。
(5)统计各梯的运行与空闲时间;统计各人发出乘梯要求后的等待时间;仿真结束后显示这些时间。
(6)参数K、N、M、S、T应从命令行输入。
(7)(选做)考虑有些乘客(随机决定)携带的物品体积较大,需占用1~2人的电梯空间(随机决定),且上下梯的时间比其他乘客长一倍的情况,再进行相应的仿真(注意,不是所有的乘客都携带较大体积的物品)。
这时,显示乘客及所去往的楼层时要能够识别出是否携带了较大体积的物品。
二、分析与设计模型
1.分析过程
(1)根据问题域中所描述的内容,可以生成一张“电梯楼层可达表”,其中“1”表示它所在列所对应的电梯可到达它所在行对应的楼层,如下所示:
E0
E1
E2
E3
E4
E5
E6
E7
E8
E9
F1
1
1
1
1
1
1
1
1
1
1
F2
1
1
1
1
1
1
F3
1
1
1
1
1
1
F4
1
1
1
1
1
1
F5
1
1
1
1
1
1
F6
1
1
1
1
1
1
F7
1
1
1
1
1
1
F8
1
1
1
1
1
1
F9
1
1
1
1
1
1
F10
1
1
1
1
1
1
F11
1
1
1
1
1
1
F12
1
1
1
1
1
1
F13
1
1
1
1
1
1
F14
1
1
1
1
1
1
F15
1
1
1
1
1
1
F16
1
1
1
1
1
1
F17
1
1
1
1
1
1
F18
1
1
1
1
1
1
F19
1
1
1
1
1
1
F20
1
1
1
1
1
1
F21
1
1
1
1
1
1
F22
1
1
1
1
1
1
F23
1
1
1
1
1
1
F24
1
1
1
1
1
1
F25
1
1
1
1
1
1
1
1
F26
1
1
1
1
1
1
F27
1
1
1
1
1
1
F28
1
1
1
1
1
1
F29
1
1
1
1
1
1
F30
1
1
1
1
1
1
F31
1
1
1
1
1
1
F32
1
1
1
1
1
1
F33
1
1
1
1
1
1
F34
1
1
1
1
1
1
F35
1
1
1
1
1
1
F36
1
1
1
1
1
1
F37
1
1
1
1
1
1
F38
1
1
1
1
1
1
F39
1
1
1
1
1
1
F40
1
1
1
1
1
1
(2)根据问题域中所描述的内容,在系统中识别出了三种不同的事物,分别是乘客,电梯和楼层。
开始仿真后,对于某一个乘客,如果他不在楼层中,那么就一定在电梯中。
这样就可以将楼层和电梯都看作是包含容器和其他数据和标志的对象,在这些对象的容器中存放的就是乘客。
(3)将楼层看作是容器时,发现楼层对象内部的容器可以按作用分为两大类,一类是存放在该层随机停留的乘客的容器,另一类是存放在该层等待电梯的乘客的容器。
其中,第二类容器又可以按照乘客是向上还是向下分为两类,一类是存放等待向上乘客的容器,另一类是存放等待向下乘客的容器。
总结起来,楼层内部的容器共可以分为三类:
随机停留容器、等待向上容器和等待向下容器。
根据楼层包含这三种容器中的哪几种的不同,可以将楼层分为三类:
a.底层楼层。
乘客在底层楼层中只能够随机停留或者乘梯向上运动,所以底层楼层只包含两种容器:
随机停留容器和等待向上容器。
b.中间楼层
乘客在中间楼层可以随机停留,并且乘客既可以乘梯向上运动,又可以乘梯向下运动,所以中间楼层中包含三种容器:
随机停留容器、等待向上容器和等待向下容器。
c.顶层楼层
乘客在顶层楼层中只能够随机停留或者乘梯向下运动,所以顶层楼层只包含两种容器:
随机停留容器和等待向下容器。
又因为每个楼层的可到达电梯是不同的,所以在楼层类型的内部定义一个vector,初始化的时候该vector为空,然后通过查看楼层电梯可达表再填充该vector的内容,里面存储了所有可到达该楼层的电梯的信息。
(4)将电梯看作是容器时,所有电梯都可以使用一个类型来表示了。
在电梯类型中,定义一个vector,初始化的时候该vector为空,然后通过查看楼层电梯可达表再填充该vector的内容,里面存储了该电梯可到达的所有楼层的信息。
(5)对于乘客来说,乘客当前在某一楼层,打算去另一楼层。
乘客知道当前所在楼层的所有电梯中有哪些可以到达自己想要去的楼层,并且会对这些所有可以可到达的电梯都发出与自己目标方向相同的乘梯请求。
当某一电梯到达乘客所在楼层时,若该电梯可到达乘客要去的楼层,并且现在的运动方向与乘客的目标方向相同,并且现在排在该乘客前方的乘客没有上该电梯,并且该电梯不满时,乘客才会上该电梯。
如果乘客正在等待上电梯,而同时又有另一部满足条件的电梯到达,并且现在没有人上下,那么乘客就直接上另一部电梯,而不是等待原来那部电梯。
这样就可以保证乘客总是可以乘坐最早到达该层的的电梯,而不是死等某一固定电梯到达。
2.系统中重要类的识别
根据上述分析,在系统中识别出来的主要有三个类:
电梯类Elevator,楼层类Floor和乘客类Passenger。
其中Elevator类是对各类电梯的抽象,它封装了各类电梯的数据结构和方法。
Floor类是一个虚基类,在该类中定义了各类操作的公共接口;由Floor类派生出三个子类,分别为BottomFloor类,MiddleFloor类和TopFloor类,分别为对底层楼层、中间楼层和顶层楼层的抽象,分别封装了底层楼层、中间楼层和顶层楼层的数据机构和方法。
Passenger类是对不同乘客的抽象,它封装了乘客的数据结构和方法。
3.系统中的类图
4.类间交互过程
在系统中定义乘客、楼层和电梯三种对象。
乘客按下该楼层乘梯按钮发出乘梯请求,楼层将该乘梯请求通知相应电梯,电梯响应请求,到达该楼层时通知该楼层电梯到达,该楼层通知等待的乘客电梯到达。
乘客上电梯后电梯离开,通知楼层电梯离开,楼层通知所有在该层等待的乘客电梯离开。
乘客在电梯内设置目标楼层号,电梯载乘客到达目标楼层后通知乘客电梯到达,乘客下电梯。
5.乘客及电梯的状态迁移图
(1)乘客的状态迁移图
乘客有11种不同的状态,分别是“仿真开始前”,“随机停留”,“等待电梯到达”,“等待上电梯”,“正在上电梯”,“等待电梯运行”,“随电梯向目标层运动”,“随电梯在非目标层停止”,“等待下电梯”,“正在下电梯”和“仿真结束”。
这些状态只有在时钟每秒触发的时候才会发生相应转换,如果乘客的当前状态没有转为另一个状态,则表示乘客维持当前状态不变。
对某一个乘客仿真开始前,乘客的状态是“仿真开始前”。
当乘客进入大楼,对乘客的仿真开始,乘客的状态置为“随机停留”。
当乘客的当前状态为“随机停留”,并且乘客的仿真次数还没有到达设定的最大值,那么当乘客的停留时间到,如果此时没有符合乘客乘梯要求的电梯到达,乘客的状态转为“等待电梯到达”;如果此时有符合乘客乘梯要求的电梯到达,并且此时电梯中没有人上下,那么乘客的状态改为“正在上电梯”;如果此时电梯中有人正在下电梯或者乘客前方的人正在上电梯,那么乘客的状态改为“等待上电梯”。
当乘客的当前状态为“等待上电梯”,而此时已没有人再下电梯,并且前面的乘客也都已经上了电梯,那么乘客的状态转为“正在上电梯”;而如果乘客的当前状态为“等待上电梯”,而电梯已满并且离开,那么乘客的状态转为“等待电梯到达”。
当乘客的当前状态为“正在上电梯”,如果已经完成上电梯活动,并且后面的乘客不再上电梯,那么乘客的状态转为“随电梯向目标层运动”;如果后面的乘客仍然在上电梯,那么乘客的状态转为“等待电梯运动”。
当乘客的当前状态为“等待电梯运动”,而所有乘客都已经完成上电梯活动,电梯开始运动,乘客的状态改为“随电梯向目标层运动”。
当乘客的当前状态为“随电梯向目标层运动”,电梯在某层停下,如果该层不是乘客的目标层,那么乘客的状态转为“随电梯停留”;如果该层是乘客的目标层,如果前面有人下电梯,那么乘客的状态转为“等待下电梯”;如果前面没有人下电梯,乘客的状态转为“正在下电梯”。
如果乘客的当前状态为“等待下电梯”,前面乘客已经下电梯完毕,那么乘客状态转为“正在下电梯”。
如果乘客的当前状态为“正在下电梯”,并且已经下电梯结束,那么乘客的当前状态转为“随机停留”。
如果乘客的当前状态为“随机停留”,并且乘客的仿真次数已经到达了设定的最大值,那么乘客的状态转为“结束仿真”。
(2)电梯状态迁移图
仿真开始前,电梯的状态为“停止”。
当仿真开始后,电梯的状态为“停止”,如果电梯按照运行规则查找到的目标楼层是当前楼层上方的楼层,那么电梯的状态转为“向上运动”;如果目标楼层是下方的楼层,那么电梯的当前状态转为“向下运动”;如果目标楼层就是“当前楼层”,那么电梯的状态转为“在某层停留”。
如果电梯的当前状态为“向上运动”,电梯已经到达目标层,那么电梯的状态转为“在某层停留”。
如果电梯的当前状态为“向下运动”,电梯已经到达目标层,那么电梯的状态转为“在某层停留”。
如果电梯的当前状态为“在某层停留”,上下乘客结束,电梯查找下一目标层,如果下一目标层为上方楼层,那么电梯的状态转为“向上运动”;如果下一目标层为下方楼层,那么电梯的状态转为“向下运动”;如果找不到目标楼层,那么说明电梯现在没有乘客使用,电梯的状态转为“停止”。
三、标识符命名规则
1.类的命名规则
类的命名形式为“类名的意义单词”,类名中单词的首字母大写。
例如:
Elevator,Floor,Passenger。
2.成员函数命名规则
类中成员函数的命名规则为“x_代表成员函数的功能的单词组合”,其中x为字母e时,表示为Elevator电梯类的成员函数;x为字母f时,表示为Floor楼层类的成员函数;x为字母p时,表示为Passenger乘客类的成员函数。
单词组合中每个单词首字母大写。
比如:
e_FindDestinationFloor(),f_NoticeElevatorLeaveUp(),p_GetInBuilding()。
3.数据成员命名规则
类中数据成员的命名规则为“x_表示其功能与含义的单词组合”,其中x为字母e时,表示为Elevator电梯类的数据成员;x为字母f时,表示为Floor楼层类的数据成员;x为字母p时,表示为Passenger乘客类的数据成员。
单词组合中每个单词首字母大写。
如e_CurrentPassengerAmount,f_FloorNumber,p_RandomStayingTime。
4.局部变量命名规则
局部变量用小写单词表示,成员函数参数使用“X_表示其功能与含义的单词组合”,其中X为字母E时,表示为Elevator电梯类的成员函数的参数;X为字母F时,表示为Floor楼层类的成员函数的参数;X为字母P时,表示为Passenger乘客类的成员函数的数据成员。
单词组合中每个单词首字母大写。
如E_FloorNumber,F_ElevatorNumber,P_ElevatorNumber。
总之,系统中所有标识符都做到了见其名能知其义。
四、系统中重要类及方法的说明
1.Elevator类的说明
它是系统中各种电梯的抽象。
有如下属性和方法:
对该类的说明如下:
classElevator
{
private:
staticinte_TimeNeedPerFloor;//电梯每上或下一层所需要的时间
staticinte_MaxPassengerAmount;//电梯的最大容客量
inte_ElevatorNumber;//电梯编号
inte_CurrentPassengerAmount;//电梯内当前乘客数目
ElevatorStatee_CurrentState;//电梯当前状态
Directione_Direction;//电梯运行方向
Directione_ArrivedDirection;//电梯下一步的运行方向
inte_CurrentFloorNumber;//当前楼层编号
inte_DestinationFloorNumber;//目标楼层编号
inte_NextFloorNumber;//下一楼层编号
inte_TimeNeedToNextFloor;//到下一楼层所需要的时间
inte_TimeNeedToNextFloorStepCounter;//从当前楼层出发向下一楼层运动已经经过的时间(计数器)
inte_StayFreeTimeCounter;//电梯在某层停留时没有人上下的时间计数器
boole_bBusy;//是否有人上下的标志
boole_bFull;//电梯是否已满的标志
inte_TotalRunTime;//总运行时间
inte_TotalStopTime;//总停止时间
inte_NearestDestinatedFloorNumber;//电梯内乘客所要到达的楼层中最近的楼层
inte_NearestRequestedFloorNumber;//查找到的最近的发出乘梯请求的楼层
inte_FarestRequestedFloorNumber;//查找到的最远的发出乘梯请求的楼层
inte_ElevatorRelatedFloorSize;//电梯可到达楼层的数目
vectore_RelatedFloorVector;//电梯可达到楼层及其相应的标志
public:
Elevator(intE_ElevatorNumber);//构造函数
~Elevator();//析构函数
staticvoide_SetTimeNeedPerFloor(intE_TimeNeedPerFloor);//设置电梯运行速度(多少秒一层)的函数接口
staticvoide_SetMaxPassengerAmount(intE_MaxPassengerAmount);//设置电梯最大容客量的函数接口
voide_Simulation();//电梯仿真函数接口
voide_GetSummary();//仿真结束后显示电梯运行时间与空闲时间的函数接口
voide_PrintCurrentState();//打印电梯当前状态的函数接口
voide_FindDestinationFloor();//按照既定运行规则查找电梯下一目标楼层的函数接口
voide_AddRelatedFloor(intE_FloorNumber,Floor*E_FloorPtr);//添加电梯可到达楼层的函数接口
voide_MakeUpRequest(intE_FloorNumber);//响应楼层向上乘梯请求的函数接口
voide_MakeDownRequest(intE_FloorNumber);//响应楼层向下乘梯请求的函数接口
voide_NoticeElevatorArriveUp(intE_FloorNumber);//通知E_FloorNumber楼层此电梯到达并且继续向上运动的函数接口
voide_NoticeElevatorArriveDown(intE_FloorNumber);//通知E_FloorNumber楼层此电梯到达并且继续向下运动的函数接口
voide_NoticeElevatorLeaveUp(intE_FloorNumber);//通知E_FloorNumber楼层此电梯离开并且继续向上运动的函数接口
voide_NoticeElevatorLeaveDown(intE_FloorNumber);//通知E_FloorNumber楼层此电梯离开并且继续向下运动的函数接口
voide_AddPassenger(intE_FloorNumber,Passenger*E_PassengerPtr);//向电梯中添加乘客的函数接口,乘客上电梯时调用该函数
voide_RemovePassenger(intE_FloorNumber,Passenger*E_PassengerPtr);//从电梯中删除乘客的函数接口,乘客下电梯时调用该函数
voide_SetDestinationFloor(intE_DestinationFloorNumber);//设置目标楼层的函数接口,乘客设置目标楼层时调用该函数
voide_SetElevatorBusy();//乘客上下电梯时调用该函数,表示电梯现在被占用,其他乘客不能访问
voide_SetElevatorFree();//乘客上下电梯时调用该函数,表示电梯现在没有被占用,其他乘客可以访问
inte_GetTotalRunTime();//获取电梯总运行时间的函数接口
inte_GetTotalStopTime();//获取电梯总停止时间的函数接口
ElevatorStatee_GetCurrentState();//获取电梯当前状态的函数接口
inte_GetCurrentFloorNumber();//获取电梯当前所在楼层的函数接口
boole_IsFull();//判断电梯当前是否已满的函数接口
boole_IsBusy();//判断电梯当前是否被占用的函数接口
voide_RemoveInvalidPassenger();//由电梯自己调用,删除已经下电梯的失效乘客
};
2.Floor类的说明
2.1Floor基类
Floor类是一个虚基类,它定义了楼层所提供的操作的接口,如下所示:
对该类的说明如下:
classFloor
{
public:
virtualvoidf_Simulation()=0;//楼层仿真函数接口
virtualvoidf_PrintCurrentState()=0;//打印楼层当前状态的函数接口
virtualintf_GetFloorNumber()=0;//获取楼层号的函数接口
virtualvoidf_MakeRequest(intF_ElevatorNumber,DirectionF_RequestDir)=0;//发出请求函数接口,供乘客发出乘梯请求时调用
virtualvoidf_NoticeElevatorArrive(intF_ElevatorNumber,DirectionF_ElevatorDir)=0;//通知在本层等待的乘客电梯到达
virtualvoidf_NoticeElevatorLeave(intF_ElevatorNumber,DirectionF_ElevatorDir)=0;//通知在本层等待的乘客电梯离开
virtualvoidf_AddPassengerToStayingContainer(Passenger*F_PassengerPtr)=0;//添加乘客到停留容器里,供乘客进入停留容器时调用
virtualvoidf_RemovePassengerFromStayingContainer(Passenger*F_PassengerPtr)=0;//从停留容器中移除乘客,供乘客停留时间到时进入等待容器时调用
virtualvoidf_AddPassengerTo