NCHU电梯调度Blog
NCHU电梯调度Blog
一、前言
对这三次题目集的总结:
这番作业的难度,恰似那层层叠嶂的山峦,一步更比一步高。题目数量倒也妥帖,给予的时日亦算充裕。先前的基础题目,仿若垒砌积木,领着我们一步步熟稔如何设计类与对象;然每回的末道题目,却似陡然升起的险关,真真要考究一番真才实学。头一遭的电梯题目,单是弄明白这电梯该如何进行智能调度,便得反复思量、琢磨,调试代码至夜半时分,倒成了寻常之事。不过,咬着牙啃下这硬骨头后,后续两次的迭代题目,竟生出几分轻松之感来。此时,重点已然转为优化设计:如何将不同类的任务拆解开来,又怎样方能叫算法运行得更为流畅。这种从「被按在地上摩擦」到「游刃有余走位」的蜕变感,比通关游戏拿到成就还带劲!
二、1.设计与分析
(一)1.1第一次电梯题目的设计与分析
1.1.1题目要求:
设计一个电梯类,具体包含电梯的最大楼层数、最小楼层数(默认为1层)当前楼层、运行方向、运行状态,以及电梯内部乘客的请求队列和电梯外部楼层乘客的请求队列,其中,电梯外部请求队列需要区分上行和下行。
电梯运行规则如下:电梯默认停留在1层,状态为静止,当有乘客对电梯发起请求时(各楼层电梯外部乘客按下上行或者下行按钮或者电梯内部乘客按下想要到达的楼层数字按钮),电梯开始移动,当电梯向某个方向移动时,优先处理同方向的请求,当同方向的请求均被处理完毕然后再处理相反方向的请求。电梯运行过程中的状态包括停止、移动中、开门、关门等状态。当电梯停止时,如果有新的请求,就根据请求的方向或位置决定移动方向。电梯在运行到某一楼层时,检查当前是否有请求(访问电梯内请求队列和电梯外请求队列),然后据此决定移动方向。每次移动一个楼层,检查是否有需要停靠的请求,如果有,则开门,处理该楼层的请求,然后关门继续移动。
使用键盘模拟输入乘客的请求,此时要注意处理无效请求情况,例如无效楼层请求,比如超过大楼的最高或最低楼层。还需要考虑电梯的空闲状态,当没有请求时,电梯停留在当前楼层。
请编写一个Java程序,设计一个电梯类,包含状态管理、请求队列管理以及调度算法,并使用一些测试用例,模拟不同的请求顺序,观察电梯的行为是否符合预期,比如是否优先处理同方向的请求,是否在移动过程中处理顺路的请求等。为了降低编程难度,不考虑同时有多个乘客请求同时发生的情况,即采用串行处理乘客的请求方式(电梯只按照规则响应请求队列中当前的乘客请求,响应结束后再响应下一个请求),具体运行规则详见输入输出样例。
根据题目设计的类图:

1.1.2类的总体设计
Main类:用string把数据读入,使用正则表达式来正确判断每行输入当中所需的数据,然后按数据的形式来判断是外部还是内部的请求。
Elevator类:该类储存了内外请求,同时用来控制电梯的运行,和方向的确定,以及打印电梯当前所在的楼层、状态和运行方向。
State类:该类用于储存内外请求的状态。
Source Monitor分析结果:

1.1.3分析与心得
由上面的Source Monitor分析的结果来看不难发现,这次题目集提交的通过代码的存在的主要问题有这几个:
- 方法相关问题
缺少方法:报告中显示 “{no methods}” 且 “Maximum Complexity” 为 0、“Average Complexity” 为 0,这表明代码里或许没有定义方法,或者方法定义存在缺失。在 Java 编程中,方法是实现功能的关键部分,缺少方法会让代码难以复用和维护。
方法数量与分布:虽然报告提到 “Methods per Class” 为 2.00,但整体没有检测到方法,这可能意味着类中的方法定义不规范或者存在语法错误,从而导致指标工具无法识别。 - 代码复杂度问题
整体复杂度低:最大复杂度和平均复杂度都为 0,这可能暗示代码的逻辑较为简单,也许没有实现足够复杂的业务逻辑。对于一个完整的项目而言,这可能意味着功能不完整。
分支语句占比:“Percent Branch Statements” 达到 40.2%,比例相对较高。这可能表明代码里有较多的条件判断,可能会使代码的可读性和可维护性降低。 - 注释问题
注释比例:“Percent Lines with Comments” 为 29.4%,注释比例相对较高。虽然注释有助于理解代码,但过多的注释可能意味着代码本身的可读性欠佳,或者注释没有准确反映代码的功能。 - 代码结构问题
代码块深度:“Maximum Block Depth” 达到 5,且 “Line Number of Deepest Block” 为 241,这表明代码里存在嵌套较深的代码块。深度嵌套的代码块会让代码的可读性变差,并且容易引入逻辑错误。
改进措施:
方法定义:要保证代码里正确定义了方法,并且方法的命名和参数要符合 Java 的编码规范。
复杂度控制:对分支语句进行优化,可考虑使用多态、策略模式等设计模式来减少条件判断。
注释优化:检查注释是否准确反映了代码的功能,避免过多无意义的注释。
代码结构优化:减少代码块的嵌套深度,可以通过提取方法、拆分逻辑等方式来简化代码结构。
(二)1.2第二次电梯题目的设计与分析
1.2.1题目要求:对之前电梯调度程序进行迭代性设计,目的为解决电梯类职责过多的问题,类设计要求遵循单一职责原则(SRP),要求必须包含但不限于设计电梯类、乘客请求类、队列类以及控制类。电梯运行规则与前阶段单类设计相同,但要处理如下情况:
乘客请求楼层数有误,具体为高于最高楼层数或低于最低楼层数,处理方法:程序自动忽略此类输入,继续执行
乘客请求不合理,具体为输入时出现连续的相同请求,例如<3><3><3>或者<5,DOWN><5,DOWN>,处理方法:程序自动忽略相同的多余输入,继续执行,例如<3><3><3>过滤为<3>
根据题目设计的类图:

1.2.2类的总体设计
Main类:用string把数据读入,使用正则表达式来正确判断每行输入当中所需的数据,然后按数据的形式来判断是外部还是内部的请求。
State类:该类用于储存内外请求的状态。
Elevator 类:电梯实体模拟。记录当前楼层(currentFloor)、运行方向(direction)、可运行楼层范围(minFloor/maxFloor)。moveToFloor:根据目标楼层和当前方向控制电梯移动,输出运行过程(移动、开关门)。提供方向切换接口(setDirection),支持调度逻辑调整电梯运行方向。
RequestQueue 类:请求队列管理器。internalRequests:管理电梯内部乘客的楼层请求(无方向)。externalRequests:管理电梯外部候梯人员的请求(含方向)。在添加请求时检查楼层是否在有效范围(minFloor~maxFloor),过滤无效请求。提供 removeRequest 方法移除已处理的请求,确保队列中仅包含待处理任务。
ElevatorController 类:电梯调度核心。关联 Elevator 和 RequestQueue,作为两者的桥梁。processRequests 循环处理请求队列中的任务,直至队列为空。getNextRequest 根据电梯当前状态(楼层、方向)选择下一个处理的请求,实现简单的调度策略(方向优先、距离优先)。
Source Monitor分析结果:

1.1.3分析与心得
从提供的代码指标数据来看,相比之前的版本,代码结构和复杂度有一定改善,但仍存在一些可优化的方向。
行数(381 行)和语句数(143 句):代码规模略有增加,可能是因为新增了逻辑或注释,但整体仍属于中等复杂度。
类数量保持为 2 个(与前一版本相同),但Methods per Class(5.5) 提升,说明单个类的方法数量增多(可能是拆分了部分逻辑到更多方法中)。
Average Statements per Method(12.27) 较前一版本(24)明显下降,表明方法粒度更细,符合「单一职责原则」,代码可维护性提升。
复杂度指标
Maximum Complexity(0)和 Average Complexity(0):仍显示无方法复杂度数据,可能是代码中方法未被正确识别(如方法定义不规范)或指标工具限制。
Branch Statements(33.6%):分支语句比例下降(前一版本为 40.2%),说明条件判断逻辑有所简化,代码可读性可能提升。
Block Depth(最大块深度 4):较前一版本(最大 5)降低,嵌套层级减少,逻辑结构更扁平,但第 314 行仍存在 4 层嵌套,需注意深层嵌套的可读性问题。
潜在问题与需要改的进点
1.方法定义与识别问题
指标显示 No Methods Found: Complexity,可能原因:
方法命名不符合规范(如使用特殊符号、关键字)。
方法内部逻辑被注释包裹,或存在语法错误导致工具无法解析。
2.分支逻辑与代码块深度
33.6% 的分支语句 仍占比较高,可能存在冗余的条件判断。例如:
多层 if-else 嵌套未抽象为独立方法或策略模式。
重复判断同一条件(如方向、楼层范围)。
最大块深度 4:虽然低于前一版本,但深层嵌套(如 4 层 if)仍可能导致「面条式代码」。
将复杂逻辑拆分为更小的方法(如将调度策略拆分为 getUpDirectionRequest() 和 getDownDirectionRequest())。
3.注释与可读性
26.2% 的注释行比例 适中,但需注意:
注释是否准确描述代码逻辑(避免「冗余注释」,如注释 // 增加内部请求 对应清晰的方法名 addInternalRequest)。
4.类职责与设计模式
两个类(如 ElevatorController 和 RequestQueue)的职责不够清晰。
心得:
当前代码在方法拆分和嵌套层级上有一定改进,但仍存在方法识别异常、分支逻辑复杂等问题。通过引入设计模式、进一步解耦职责和优化嵌套结构,可显著提升代码的可维护性和扩展性。还需要加强结合具体代码逻辑,优先处理方法定义问题的能力,再逐步重构调度策略部分。
(三)1.3第三次电梯题目的设计与分析
1.3.1题目要求:对之前电梯调度程序再次进行迭代性设计,加入乘客类(Passenger),取消乘客请求类,类设计要求遵循单一职责原则(SRP),要求必须包含但不限于设计电梯类、乘客类、队列类以及控制类。电梯运行规则与前阶段相同,但有如下变动情况:乘客请求输入变动情况:外部请求由之前的<请求楼层数,请求方向>修改为<请求源楼层,请求目的楼层>对于外部请求,当电梯处理该请求之后(该请求出队),要将<请求源楼层,请求目的楼层>中的请求目的楼层加入到请求内部队列(加到队尾)。
根据题目设计的类图:

1.3.2类的总体设计
Main类:用string把数据读入,使用正则表达式来正确判断每行输入当中所需的数据,然后按数据的形式来判断是外部还是内部的请求,并将转化出外部请求的方向。
State类:该类用于储存内外请求的状态。
Elevator 类:电梯实体模拟。记录当前楼层(currentFloor)、运行方向(direction)、可运行楼层范围(minFloor/maxFloor)。moveToFloor:根据目标楼层和当前方向控制电梯移动,输出运行过程(移动、开关门)。提供方向切换接口(setDirection),支持调度逻辑调整电梯运行方向。
Passenger 类:请求队列管理器。internalRequests:管理电梯内部乘客的楼层请求(无方向)。externalRequests:管理电梯外部候梯人员的请求(含方向)。在添加请求时检查楼层是否在有效范围(minFloor~maxFloor),过滤无效请求。提供 removeRequest 方法移除已处理的请求,确保队列中仅包含待处理任务。
ElevatorController 类:电梯调度核心。关联 Elevator 和 RequestQueue,作为两者的桥梁。processRequests 循环处理请求队列中的任务,直至队列为空。getNextRequest 根据电梯当前状态(楼层、方向)选择下一个处理的请求,实现简单的调度策略(方向优先、距离优先)。
Source Monitor分析结果:

1.1.3分析与心得
ElevatorController 与 Passenger/RequestQueue 强耦合,调度逻辑直接操作请求队列的具体实现(如ArrayList的get(0)),违反依赖倒置原则。
Passenger类职责仍不清晰,同时涉及请求管理和乘客目标存储,违背单一职责原则。
心得:
设计先行:在编码前绘制类图和时序图,明确类职责和交互流程,减少编码过程中的逻辑反复。
分而治之:将大问题拆解为小模块(如先实现「方向优先调度」,再优化「距离优先」),避免一次性处理所有逻辑。
三、踩坑心得
(一)正则表达式不够熟练
在第二次过滤不正确请求的时候,因为不熟练对于正则表达式的使用,从而耗费了大量时间,感觉语法问题可以多询问ai,从而减少时间的耗费,提高效率。
(二)在循环条件中不能及时设计出退出循环的特判条件,个人感觉可以在写的过程中多进行debug,从而更好地找出代码的逻辑错误。

(三)对于分而治之的理解不够深刻,拿到题目就想像c一样直接把整个题目全部敲出,奈何自己的码力根本就不能支撑自己直接写出,既然不能直接写出,那就要学会分治,一步一步逐渐写出这个程序。

(四)对整个电梯的运行理解还是不够深刻,对look算法理解不够深刻,电梯到底如何运行一直迷迷糊糊,第一次侥幸通过了测试点,但第二次测试点数据加强之后便不能直接通过了,最后在和同学交流之后才彻底弄懂电梯的逻辑,所以在今后的学习生活中还是得多和他人交流。

四、改进建议
4.1拆分 Passenger 类职责:
新建 RequestQueue 类,专门管理请求队列(内部 / 外部),移除 targetFloor 相关逻辑。
新建 Passenger 类,用于模拟乘客行为(如进入电梯、选择目标楼层),与请求队列解耦。
4.2重构调度策略:
定义 ElevatorStrategy 接口,实现 getNextRequest() 方法,将不同调度算法(如 DirectionFirstStrategy、ShortestDistanceStrategy)封装为具体策略类。
在 ElevatorController 中通过依赖注入使用策略接口,消除 if-else 嵌套。
4.3解耦电梯执行逻辑:
将 Elevator 的输出逻辑抽象为 ElevatorLogger 接口,通过构造函数注入具体实现。
移除 moveToFloor 中对请求方向的处理,方向切换仅由调度策略决定。
4.4规范输入与请求模型:
明确外部请求格式为 <楼层,方向>(如<520,UP>),内部请求为 <楼层>,避免混淆目标楼层和方向。
在 RequestQueue 中添加请求去重逻辑(如相同楼层、相同方向的外部请求合并),避免重复处理。
五,总结
收获
- 编程基础能力提升
1.1正则表达式的工程化应用
从输入校验场景切入,学会使用正则表达式(如matches()方法)规范数据格式(如电梯请求的楼层、方向格式校验),理解其在边界条件处理中的必要性,建立「输入合法性优先」的开发思维。
1.2动态数据结构的灵活运用
通过ArrayList的高频操作(add()/remove()/get()),掌握动态数组的适用场景(如请求队列的动态增删),理解其与数组的性能差异(如remove(0)的 O (n) 时间复杂度),为后续选择更优数据结构(如LinkedList/Queue)奠定基础。 - 面向对象设计入门
2.1类与对象的建模思维
从电梯调度场景中抽象出State(请求状态)、Elevator(电梯实体)、RequestQueue(请求队列)等类,理解「数据封装」(类属性私有化)和「行为分离」(方法职责单一化)的核心原则,初步建立「用类模拟现实实体」的建模能力。
2.2类间关系的设计实践
通过ElevatorController协调Elevator与RequestQueue的依赖关系,理解「组合模式」(Has-A 关系)的应用,避免类之间的紧耦合,为复杂系统的模块协作提供思路。 - 问题拆解与逻辑实现
通过电梯调度算法的逐步迭代(从基础调度到优化设计),学会将复杂问题拆解为子任务(如请求分类、方向判断、路径选择),并通过「自顶向下」的方式逐步实现逻辑,提升结构化解决问题的能力
不足
1.算法逻辑与代码质量
过度依赖if-else的优化策略
问题本质:条件逻辑嵌套反映出「过程式编程思维」,缺乏对抽象策略的应用。
个人认为可行的改进方案:
引入策略模式,将不同调度规则(如方向优先、距离优先)封装为独立策略类,通过接口实现动态切换,消除多层if-else嵌套。
2.注释与可读性优化
问题影响:缺乏逻辑注释会导致代码「自我解释性」不足。
遵循「关键逻辑必注释,复杂算法配说明」原则,对调度策略规则(如「当前方向为 UP 时优先处理同方向请求」)、状态变更点(如电梯方向切换)添加注释。
浙公网安备 33010602011771号