第一次Blog作业
PTA题目集5-7的Blog总结:
面对对象(java)课程的第一单元结束了,在完成电梯调度相关的题目集后,我收获颇丰:
熟悉了 Java 在实际场景应用中的语法;
进一步巩固了面向对象的设计理念;
深刻体会到了程序设计中逻辑完整性的重要;
掌握了基于实际场景的测试方法。
个人观点:
个人认为本次作业主要在于正则表达式的学习以及ArrayList或ListLink的使用,在于对队列的增删改,题目的复杂更偏向于对问题的思考方法。
Complexity Metrics(复杂度分析)
方法的复杂度分析主要基于循环复杂度(v (G)),它可理解为穷尽程序流程每一条路径所需要的试验次数。Essentail Complexity(ev (G))表示一个方法的结构化程度,范围在 [1, v (G)] 之间,值越大程序结构越 “病态”。Design Complexity(iv (G))表示一个方法和它所调用的其他方法的紧密程度,范围也在 [1, v (G)] 之间,值越大联系越紧密。对于类,有 OCavg(类的方法的平均循环复杂度)和 WMC(类的总循环复杂度)两个项目。
下面我将从程序结构、测试情况以及 bug 分析几个方面来总结电梯调度相关的题目。
第一次作业(单部电梯基本调度)
作业要求
请编写一个Java程序,设计一个电梯类,包含状态管理、请求队列管理以及调度算法,并使用一些测试用例,模拟不同的请求顺序,观察电梯的行为是否符合预期,比如是否优先处理同方向的请求,是否在移动过程中处理顺路的请求等。为了降低编程难度,不考虑同时有多个乘客请求同时发生的情况,即采用串行处理乘客的请求方式(电梯只按照规则响应请求队列中当前的乘客请求,响应结束后再响应下一个请求),
实现方式
创建Elevator类来表示电梯,在类中定义属性来存储电梯的各种状态信息,通过方法来处理内部和外部乘客的请求。在处理请求时,按照电梯运行规则(优先处理内部请求和同方向请求等)进行逻辑判断和操作。例如,当有请求时,根据请求情况确定电梯运行方向,然后移动电梯,在移动过程中检查并处理各楼层的请求。
代码规模

**复杂度分析 **

问题:
一些方法如handleBothRequests、handleSameDirectionRequests、handleOppositeDirectionRequests等方法的逻辑比较复杂,包含多层嵌套的条件判断,这会导致代码可读性和可维护性降低。
改进方法:
将这些复杂方法中的部分逻辑提取成更小的、功能单一的私有方法。例如,在handleBothRequests方法中,可以将处理同方向请求、反方向请求等逻辑提取成单独的方法。
Bug 分析
公测
暂时没有问题。
互测
在互测中,程序没有出现导致程序崩溃的错误,但存在一些逻辑不够完善的地方。例如,在处理电梯二次到达同一楼层时是不需要再输出方向的。于是,我就增加了一次判断:如果是接着多次到达同一楼层,只打印:close door。
测试方法
通过PTA上的测试案例以及老师的补充案例来测试程序的正确性。同时,对程序输出结果进行详细记录和分析,观察电梯运行过程是否符合预期。
第二次作业(单部电梯基本调度迭代)
作业要求
电梯运行规则与前阶段单类设计相同,但要处理如下情况:
1.乘客请求楼层数有误,具体为高于最高楼层数或低于最低楼层数,处理方法:程序自动忽略此类输入,继续执行
2.乘客请求不合理,具体为输入时出现连续的相同请求,例如<3><3><3>或者<5,DOWN><5,DOWN>,处理方法:程序自动忽略相同的多余输入,继续执行,例如<3><3><3>过滤为<3>
实现方法:
将原来的代码进行修改:
- 类结构的重构
代码被重构为多个类,包括ExternalRequest、RequestQueue、Elevator和Controller类。这种结构更加模块化,每个类负责特定的功能。ExternalRequest类用于表示外部请求,包含请求的楼层和方向信息。RequestQueue类用于管理请求队列,包括内部请求和外部请求,并进行请求的有效性和重复性检查。Elevator类表示电梯本身,包含电梯的状态(如当前楼层、运行方向)和请求队列。Controller类用于控制电梯的运行,处理请求的调度和电梯的移动操作。 - 请求处理的变化
现在的代码:请求的处理逻辑被移到了Controller类中。Controller类的processRequests方法负责处理请求。它通过while循环不断检查内部请求队列和外部请求队列,直到所有请求都被处理完毕。在processRequests方法中,根据内部请求和外部请求是否存在,调用不同的方法(bothrequests、onerequest)来处理请求。这些方法进一步调用其他方法来处理不同状态(如空闲、上升、下降)下的请求。 - 请求队列管理的变化
现在的代码:使用RequestQueue类来管理请求。RequestQueue类中的addRequest方法会进行请求的有效性和重复性检查。如果请求有效且不重复,才会添加到相应的请求队列(内部请求队列或外部请求队列)中。 - 电梯移动操作的变化
现在的代码:电梯移动操作的方法(elevatormove、printelevator、printdoor)被移到了Controller类中。Controller类在处理请求时调用这些方法来模拟电梯的移动和门的操作。
类图
![]()
代码规模

复杂度分析





1.多个方法具有较高的复杂度值,例如Elevator.elevatorMove方法在某些情况下复杂度较高,这表明方法内部可能有复杂的逻辑和较多的分支。可以对高复杂度的方法进行重构,尝试将复杂的逻辑拆分成更小、更简单的方法。例如,在Elevator.elevatorMove方法中,可以将处理不同方向(上、下)和不同请求类型(内部、外部)的逻辑拆分成独立的方法。
2.部分方法具有较大的最大深度(Max Depth)值,这意味着方法内部可能有多层嵌套的逻辑,增加了代码的复杂性。可减少方法中的嵌套层数,在处理请求的方法中,如果满足某些条件可以直接返回结果,而不是继续嵌套在多层条件判断中。
Bug 分析
公测
在公测中被发现多个 bug,其中一个主要 bug 是在处理请求队列时,出现优先处理楼层发生错误:优先级搞错了。这是因为我原来的代码的逻辑为:每处理完一个楼层请求时,会将电梯的方向改为:IDLE。这个是错误的,正确的逻辑为:只有每当处理完同一方向的请求后才能将电梯的运行方向进行改变。
互测
在互测中出现了性能问题。虽然程序能够正确处理请求,但在处理大量请求时,处理速度较慢。这是由于在请求处理算法中存在一些低效的操作,例如在遍历请求队列时没有采用更高效的数据结构和算法。
测试方法
通过PTA上的测试案例以及老师的补充案例来测试程序的正确性。同时,自己也通过手动输入案例对程序输出结果进行详细记录和分析,观察电梯运行过程是否符合预期。
第三次作业(单部电梯基本调度再次迭代)
作业要求
对之前电梯调度程序再次进行迭代性设计,加入乘客类(Passenger),取消乘客请求类
电梯运行规则与前阶段相同,但有如下变动情况:
乘客请求输入变动情况:外部请求由之前的<请求楼层数,请求方向>修改为<请求源楼层,请求目的楼层>
对于外部请求,当电梯处理该请求之后(该请求出队),要将<请求源楼层,请求目的楼层>中的请求目的楼层加入到请求内部队列(加到队尾)
实现方法:
从第二次电梯的代码到现在的代码,主要实现了以下改动:新增passenger类用于表示乘客信息,包含所在楼层和目标楼层;内部请求仍用LinkedList
代码规模

类图

复杂度分析





1.Controller类中的bothrequests方法的复杂度较高,特别是在处理不同方向(UP、DOWN、IDLE)时的逻辑。可以将处理不同方向的逻辑提取到独立的方法中,使bothrequests方法更简洁。
2.requestline类中的isValid方法的复杂度较高,因为它处理了两种不同类型请求(内部请求和外部请求)的验证逻辑。可将内部请求和外部请求的验证逻辑分开,分别放在不同的方法中。
3.Controller类中的processrequests方法中的while循环可能导致代码的嵌套较深,特别是在处理不同情况(内部请求和外部请求同时存在、只有内部请求、只有外部请求)时。可以提取while循环中的不同情况处理逻辑到独立的方法中,减少嵌套。
Bug 分析
公测
暂时没有问题
互测
在公测中被发现多个 bug,其中一个主要 bug 是在处理请求队列时,没有执行从外部请求队列新加入内部请求的目的楼层请求,原因是我只在原来的内部请求队列基础上增加新的楼层请求,并没有直接调用,导致这个问题。
测试方法
通过PTA上的测试案例以及老师的补充案例来测试程序的正确性。同时,自己也通过手动输入案例对程序输出结果进行详细记录和分析,观察电梯运行过程是否符合预期。
关于设计模式的思考
在本次 Java 课程第一单元的电梯调度程序编写过程中,设计模式的应用是我逐渐领悟到的关键要点。起初,我专注于实现基本的功能,并未对设计模式给予足够的重视。随着作业的不断迭代,代码的复杂度和维护难度逐渐增加,我深刻体会到了合理运用设计模式的重要性。。
在后续的学习和实践中,我将更加注重设计模式的学习和应用。我会深入研究各种设计模式的原理和适用场景,在编写代码之前,先思考是否可以应用合适的设计模式来优化代码结构。通过不断地实践和总结,提升自己运用设计模式解决实际问题的能力,从而编写出更加高质量的代码。
踩坑心得
在完成本次电梯调度程序的作业过程中,我踩了不少坑,这些经历让我收获了宝贵的经验教训。
在第一次作业中,为了实现电梯的调度逻辑,我编写了一些逻辑复杂的方法,如 handleBothRequests、handleSameDirectionRequests 等。这些方法中包含了多层嵌套的条件判断,虽然功能实现了,但代码的可读性和可维护性却大大降低。当需要修改或者扩展功能时,我发现很难理清代码的逻辑,甚至容易引入新的 bug。这让我认识到,在编写代码时,要将复杂的功能拆分成小的、功能单一的方法。 同时在编写程序时,要对业务逻辑有深入的理解,仔细考虑每一个细节,避免因为逻辑错误导致程序出现问题。同时,在编写代码后,要进行充分的测试,通过不同的测试用例来验证程序的正确性。
总之,这次作业中的这些坑让我明白了在编程过程中要注重代码的质量、逻辑的正确性、性能的优化以及设计模式的应用。只有不断地总结经验教训,才能在编程的道路上不断进步。


浙公网安备 33010602011771号