题目集五、六、七电梯程序报告总结
一、前言
1、题目集5的难点主要在对电梯的运行过程的判断这一段要想清楚才可以开始写代码,否则后面的代码没法进行
2、题目集6是在题目集5的基础上加了类的设计,只要题目集5上午电梯运行逻辑搞清楚了就只需要考虑类的设计,然后将题目集5的逻辑拆分一下,这里的难点主要是对类的设计及代码的逻辑拆分
3、题目集7在题目集6的基础上加了passenger的类,将电梯的请求放在了这个类里面,输入也做了修改,难点在于类间的调用及类的设计
4、这三次题目得底层是电梯运行规则,后面就是类的设计,在拆分成一个一个的小方法这里还是挺有难度的,需要我们有一个框架,想清楚每个方法的作用再去实现
二、作业要求
1、题目集5的要求是:
设计一个电梯类,具体包含电梯的最大楼层数、最小楼层数(默认为1层)当前楼层、运行方向、运行状态,以及电梯内部乘客的请求队列和电梯外部楼层乘客的请求队列,其中,电梯外部请求队列需要区分上行和下行。
电梯运行规则如下:电梯默认停留在1层,状态为静止,当有乘客对电梯发起请求时(各楼层电梯外部乘客按下上行或者下行按钮或者电梯内部乘客按下想要到达的楼层数字按钮),电梯开始移动,当电梯向某个方向移动时,优先处理同方向的请求,当同方向的请求均被处理完毕然后再处理相反方向的请求。电梯运行过程中的状态包括停止、移动中、开门、关门等状态。当电梯停止时,如果有新的请求,就根据请求的方向或位置决定移动方向。电梯在运行到某一楼层时,检查当前是否有请求(访问电梯内请求队列和电梯外请求队列),然后据此决定移动方向。每次移动一个楼层,检查是否有需要停靠的请求,如果有,则开门,处理该楼层的请求,然后关门继续移动。
使用键盘模拟输入乘客的请求,此时要注意处理无效请求情况,例如无效楼层请求,比如超过大楼的最高或最低楼层。还需要考虑电梯的空闲状态,当没有请求时,电梯停留在当前楼层。
请编写一个Java程序,设计一个电梯类,包含状态管理、请求队列管理以及调度算法,并使用一些测试用例,模拟不同的请求顺序,观察电梯的行为是否符合预期,比如是否优先处理同方向的请求,是否在移动过程中处理顺路的请求等。为了降低编程难度,不考虑同时有多个乘客请求同时发生的情况,即采用串行处理乘客的请求方式(电梯只按照规则响应请求队列中当前的乘客请求,响应结束后再响应下一个请求),具体运行规则详见输入输出样例。
输入格式:
第一行输入最小电梯楼层数。
第二行输入最大电梯楼层数。
从第三行开始每行输入代表一个乘客请求。
电梯内乘客请求格式:<楼层数>
电梯外乘客请求格式:<乘客所在楼层数,乘梯方向>,其中,乘梯方向用UP代表上行,用DOWN代表下行(UP、DOWN必须大写)。
当输入“end”时代表输入结束(end不区分大小写)。
输出格式:
模拟电梯的运行过程,输出方式如下:
运行到某一楼层(不需要停留开门),输出一行文本:
Current Floor: 楼层数 Direction: 方向
运行到某一楼层(需要停留开门)输出两行文本:
Open Door # Floor 楼层数
Close Door
输入样例1:
在这里给出一组输入。例如:
1
20
<2,UP>
<5>
<6,DOWN>
<7>
<3>
end
输出样例1:
在这里给出相应的输出。例如:
Current Floor: 1 Direction: UP
Current Floor: 2 Direction: UP
Open Door # Floor 2
Close Door
Current Floor: 3 Direction: UP
Current Floor: 4 Direction: UP
Current Floor: 5 Direction: UP
Open Door # Floor 5
Close Door
Current Floor: 6 Direction: UP
Current Floor: 7 Direction: UP
Open Door # Floor 7
Close Door
Current Floor: 6 Direction: DOWN
Open Door # Floor 6
Close Door
Current Floor: 5 Direction: DOWN
Current Floor: 4 Direction: DOWN
Current Floor: 3 Direction: DOWN
Open Door # Floor 3
Close Door
输入样例2:
在这里给出一组输入。例如:
1
20
<2,UP>
<2,UP>
<5>
<5>
<5>
<6,DOWN>
<7>
<7>
<3>
<22,DOWN>
<5,DOWN>
<30>
END
输出样例2:
在这里给出相应的输出。例如:
Current Floor: 1 Direction: UP
Current Floor: 2 Direction: UP
Open Door # Floor 2
Close Door
Current Floor: 3 Direction: UP
Current Floor: 4 Direction: UP
Current Floor: 5 Direction: UP
Open Door # Floor 5
Close Door
Current Floor: 6 Direction: UP
Current Floor: 7 Direction: UP
Open Door # Floor 7
Close Door
Current Floor: 6 Direction: DOWN
Open Door # Floor 6
Close Door
Current Floor: 5 Direction: DOWN
Open Door # Floor 5
Close Door
Current Floor: 4 Direction: DOWN
Current Floor: 3 Direction: DOWN
Open Door # Floor 3
Close Door
2、题目集6的要求:
在题目集5电梯调度程序的基础上进行迭代性设计
电梯运行规则与前阶段单类设计相同,但要处理如下情况:
乘客请求楼层数有误,具体为高于最高楼层数或低于最低楼层数,处理方法:程序自动忽略此类输入,继续执行
乘客请求不合理,具体为输入时出现连续的相同请求,例如<3><3><3>或者<5,DOWN><5,DOWN>,处理方法:程序自动忽略相同的多余输入,继续执行,例如<3><3><3>过滤为<3>
3、题目集7的要求:
对之前电梯调度程序再次进行迭代性设计,加入乘客类(Passenger),取消乘客请求类,类设计要求遵循单一职责原则(SRP),要求必须包含但不限于设计电梯类、乘客类、队列类以及控制类,电梯运行规则与题目集5、6相同,但有如下变动情况:
乘客请求输入变动情况:外部请求由之前的<请求楼层数,请求方向>修改为<请求源楼层,请求目的楼层>
对于外部请求,当电梯处理该请求之后(该请求出队),要将<请求源楼层,请求目的楼层>中的请求目的楼层加入到请求内部队列(加到队尾)
三、设计与分析
1、在写电梯运行逻辑时我采用了三次循环,分别判断外部请求和内部请求同时不为空的情况、外部请求为空内部请求不为空还有内部请求为空外部请求不为空的情况,然后就只比较队列头部再判断电梯的运行方向就可以。对于电梯的运行方向单独拿出一个方法进行判断,然后再将这些串联起来就可以了
2、三次代码的复杂度分析如下:
<1>、elevator.java为题目集5,从中看出其代码复杂度达到了5.5最大的复杂度达到了62,说明代码的复杂度非常的高,刚开始写的时候还不会类的设计,就全部放在了一个主类里面,在实现电梯运行的代码中使用了大量的if-else的嵌套语句,下面是题目集5类的设计:
可以看出类的设计十分的单一,只有2个,我将那个电梯的运行都放在了一个方法里,先去判断了电梯的运行方向即先比较电梯下一步是去外部请求还是内部请求,然后再去移动,但是类的设计整体来看是不太合理的,
这个是代码具体复杂度的分析:
除了类的设计在绿色方框内,其他的都不在,注释相对较少,代码的复杂度挺高的,主要是我大量的运用了if-else还有while循环就导致了代码的复杂度高,还有就是代码的深度,刚开始还没深入领悟Java我就还是采用c语言的方式来进行,电梯的运行就是还按照c语言的思路来写的
<2>、elevator1.java是题目集6的相对于题目集5简化了很多,多了很多类的设计,这个是6的类图:
将题目集5的代码进行了拆分,多设计了类将电梯的具体运行过程拆分成了多个方法,processRequests():处理所有的内部和外部请求,控制电梯的运行,包括移动电梯、确定方向、打开和关闭电梯门以及移除已处理的请求
determineDirection():根据当前电梯位置、内部和外部请求,确定电梯的运行方向。getClosest(Integer a, Integer b, ExternalRequest n):根据当前电梯位置、内部请求楼层和外部请求,确定最近的目标楼层。
openDoors(int currentfloor):在指定楼层打开电梯门。removeRequests(int currentfloor):从请求队列中移除已处理的请求
代码具体复杂度的分析:
相对与题目集5的代码,代码简化了很多,分析结果更多的在绿色方框里面,将一些复杂的逻辑简化了,使得代码更加的简洁,更加的清晰明了,但是复杂度最高的那里增加了,主要是我的代码方法的提炼不合理将一些方法设置的很简单,其他方法就相对提高了复杂度
<3>、题目集7就在题目集6的基础上将externalrequest删去了,增加了passenger,还修改了外部请求,整体和题目集6差不多就是将外部请求的目的地请求加入到内部请求的末尾,代码类图如下:
整体设计和题目集6的方法是差不多的,passenger类里面负责处理内外部的请求并加到队列里面
代码的复杂度分析如下:
可以看到代码的复杂度对于题目集6来说又简化了很多,但是我没有写出来,在类的设计是我卡住了,不知道怎么写那个方法,然后再在pocessRequest调用那些方法,passenger类里面我的代码提炼没有实现,后面的代码就进行不下去了,再control类里面我的move()和getNextRequest()方法我不太会写所以就写不出来了
四、踩坑心得
1、在处理外部请求时,外部请求是由楼层和方向组成的,我开始想的是用ArrayList储存然后list(0)就储存楼层然后list(1)就储存外部请求的方向之后移除的时候就移除list(0)和list(1)后面发现好像是不可以这样的然后我就定义了一个ExternalRequest类就处理外部请求:
然后再定义外部请求的链表是用ArrayList list2 = new ArrayList<>();这样的形式把他定义为ExternalRequest的形式
2、在处理外部相同的请求时出现了非零返回的错误:
我是想着判断list(0)和list(1)相不相等然后再移除判断下一组,然后就用了这样的方法,但是这样的结果没有考虑到flag=1这样的情况就造成了非零返回的错误正确的应该这样:
3、在处理楼层1的时候要将其单独领出来写,我开始是想着放在我的循环里面判断的后面结果就是错误的
五、改进建议
1、在题目集5中我的代码设计的类是很少的,就需要多设计一些类将代码进行拆分简化
2、题目集6中我将题目集5的代码进行了拆分,但是从那个复杂度那看还是十分的复杂,像在pocessRequest里面有很多代码重复,可提取成一个通用的方法,从而简化代码,而且pocessRequest里面主要是调用其他的方法的,但是我还是将一些电梯请求的代码放在里面这里还需要继续拆分
3、在电梯的目的地方向的判断里和电梯下一步是去内部请求那还是外部请求那我使用了大量的if-else语句嵌套是得代码变得十分的复杂冗长,而且这样写很容易出错,当时我在写的时候就很容易的漏了情况没考虑,所以在下次写代码的时候要尽可能的减少if-else的使用
4、一个好的代码是每个方法最长不超过60行的,但是我的代码好几个方法都超过了60行,所以可以看出我的代码的方法拆分的还是不够的彻底,还需要进一步的优化
5、这次的代码其实还没有做到单一职责原则,我还没有完全掌握这一要求,所以很多都是凭借自己的想法去写的,还有就是按照c语言的思路来写还没进入Java的模式,之后要深入运用Java知识
六、总结
1、通过这次实验我收获了挺多的,掌握了许多知识,收获颇丰:
<1>、学会了该怎么去细化类从而使代码变得更加简单且清晰明了
<2>、学习到了类间关系该怎么去调用
<3>、学到了正则表达式将数字和字符串等单独提取出来以及字符串的匹配
<4>、学会了用ArrayList对队列的增加和删除操作
这三次的题目集训练是层层输入的,通过这次的迭代训练不仅锻炼了我对电梯的逻辑思考能力还训练了我对类的设计,虽然在题目集6和题目集7里都提供了类的设计,但是里面的具体设计还是得我们进行思考,这也是这3次题目里的一大难点,对我们的思维方法要求还挺高的,还有就是代码要符合单一职责原则,这也是面向对象的要求。总而言之,这次的收获还挺大的,让我们对Java这门课有了一个清晰的了解,初步地掌握了面向对象的概念。
2、在之后的学习里要重点去学一下类的设计,对于这一块掌握的还不是很好,还去学习一下Java的一些基础知识