电梯调度问题

经历了三次电梯调度问题作业,需要我们用到两个队列,一个内部请求一个外部请求,同时需要我们设计不同的类方便后面的迭代,综合来说,对我个人还是比较难的。这里把我的一点心得分享给大家。
第一次电梯调度作业:设计一个电梯类,具体包含电梯的最大楼层数、最小楼层数(默认为1层)当前楼层、运行方向、运行状态,以及电梯内部乘客的请求队列和电梯外部楼层乘客的请求队列,其中,电梯外部请求队列需要区分上行和下行。
第二次电梯调度作业:对之前电梯调度程序进行迭代性设计,目的为解决电梯类职责过多的问题,类设计要求遵循单一职责原则(SRP),要求必须包含但不限于设计电梯类、乘客请求类、队列类以及控制类。
第三次电梯调度作业:对之前电梯调度程序再次进行迭代性设计,加入乘客类(Passenger),取消乘客请求类,类设计要求遵循单一职责原则(SRP),要求必须包含但不限于设计电梯类、乘客类、队列类以及控制类。

第一次作业:
题干:设计一个电梯类,具体包含电梯的最大楼层数、最小楼层数(默认为1层)当前楼层、运行方向、运行状态,以及电梯内部乘客的请求队列和电梯外部楼层乘客的请求队列,其中,电梯外部请求队列需要区分上行和下行。
电梯运行规则如下:电梯默认停留在1层,状态为静止,当有乘客对电梯发起请求时(各楼层电梯外部乘客按下上行或者下行按钮或者电梯内部乘客按下想要到达的楼层数字按钮),电梯开始移动,当电梯向某个方向移动时,优先处理同方向的请求,当同方向的请求均被处理完毕然后再处理相反方向的请求。电梯运行过程中的状态包括停止、移动中、开门、关门等状态。当电梯停止时,如果有新的请求,就根据请求的方向或位置决定移动方向。电梯在运行到某一楼层时,检查当前是否有请求(访问电梯内请求队列和电梯外请求队列),然后据此决定移动方向。每次移动一个楼层,检查是否有需要停靠的请求,如果有,则开门,处理该楼层的请求,然后关门继续移动。
使用键盘模拟输入乘客的请求,此时要注意处理无效请求情况,例如无效楼层请求,比如超过大楼的最高或最低楼层。还需要考虑电梯的空闲状态,当没有请求时,电梯停留在当前楼层。
请编写一个Java程序,设计一个电梯类,包含状态管理、请求队列管理以及调度算法,并使用一些测试用例,模拟不同的请求顺序,观察电梯的行为是否符合预期,比如是否优先处理同方向的请求,是否在移动过程中处理顺路的请求等。为了降低编程难度,不考虑同时有多个乘客请求同时发生的情况,即采用串行处理乘客的请求方式(电梯只按照规则响应请求队列中当前的乘客请求,响应结束后再响应下一个请求),具体运行规则详见输入输出样例。
输入格式:
第一行输入最小电梯楼层数。
第二行输入最大电梯楼层数。
从第三行开始每行输入代表一个乘客请求。

电梯内乘客请求格式:<楼层数>
电梯外乘客请求格式:<乘客所在楼层数,乘梯方向>,其中,乘梯方向用UP代表上行,用DOWN代表下行(UP、DOWN必须大写)。
当输入“end”时代表输入结束(end不区分大小写)。
输出格式:
模拟电梯的运行过程,输出方式如下:

运行到某一楼层(不需要停留开门),输出一行文本:
Current Floor: 楼层数 Direction: 方向
运行到某一楼层(需要停留开门)输出两行文本:
Open Door # Floor 楼层数
Close Door
重点:(end不区分大小写)可能有人不会注意,这个可能是你代码没通过的一个原因。解决后,如果你过了他的测试样例但是你结果仍然错误,这时不要在意他的测试点了,我通过同学的帮助,它们提供了一个测试样例
20
❤️,UP>
<5>
<6,DOWN>
<1>
<5>
❤️,UP>
END

Current Floor: 1 Direction: UP
Current Floor: 2 Direction: UP
Current Floor: 3 Direction: UP
Open Door # Floor 3
Close Door
Current Floor: 4 Direction: UP
Current Floor: 5 Direction: UP
Open Door # Floor 5
Close Door
Current Floor: 4 Direction: DOWN
Current Floor: 3 Direction: DOWN
Current Floor: 2 Direction: DOWN
Current Floor: 1 Direction: DOWN
Open Door # Floor 1
Close Door
Current Floor: 2 Direction: UP
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
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
用这个测试样例测试我的代码时,会发现我的代码在面对两个<5>,<5>时候会把第二个<5>,在队列中删除,如果你们面临着题目给的测试样例通过,但是答案错误,不妨用用这个测试样例,如果你的代码这个样例也能通过,应该就没有什么问题了,希望对你有所帮助。
屏幕截图 2025-11-21 112851
类的设计:Direction类:枚举电梯运行方向(上 / 下 / 空闲),ElevatorState类:枚举电梯运行状态(停止 / 移动),标记电梯当前动作状态 OuterRequest 封装电梯外部呼叫请求(目标楼层 + 呼叫方向)Elevator电梯类,Main类:负责:1. 读取用户输入(最小 / 最大楼层、内 / 外部请求)2. 初始化Elevator实例3. 触发电梯调度主流程
plantuml

第二次作业:
对之前电梯调度程序进行迭代性设计,目的为解决电梯类职责过多的问题,类设计要求遵循单一职责原则(SRP),要求必须包含但不限于设计电梯类、乘客请求类、队列类以及控制类
image
image
图片中也可以看出,我的代码复杂程度高,逻辑嵌套过深。这也是我的代码的缺点和要弥补的地方,图片中显示 Classes and Interfaces = 8,代码中实际包含 Direction、ElevatorState、OuterRequest、InnerRequest、RequestQueue、Elevator、ElevatorController、Main 共 8 个类型。最大块深度:Maximum Block Depth = 5,表示代码中嵌套最深的 if-else、循环等结构有 5 层嵌套(例如 RequestQueue 的 addOuterRequest 中包含多层条件判断)。过深的嵌套会降低代码可读性,需注意后续优化。注释比例:Percent Lines with Comments = 0.0,代码几乎无注释。虽然逻辑较直观,但长期维护或团队协作时,缺乏注释会增加理解成本,建议关键逻辑处补充说明。这也是我的不足。
代码中包含,枚举类:(Direction/ElevatorState)是基础数据类型,被请求类、电梯类依赖,无反向依赖;请求类:(InnerRequest/OuterRequest)仅被 RequestQueue 依赖,作为数据载体;RequestQueue 是请求管理中心,被 ElevatorController 依赖,不依赖其他业务类;Elevator:是实体类,被 ElevatorController 依赖,接收控制器的指令执行动作;ElevatorController:是核心调度层,依赖 Elevator 和 RequestQueue,是连接两者的桥梁;Main:是入口,依赖所有核心类,负责初始化和启动流程。

第三次作业:
对之前电梯调度程序再次进行迭代性设计,加入乘客类(Passenger),取消乘客请求类,类设计要求遵循单一职责原则(SRP),要求必须包含但不限于设计电梯类、乘客类、队列类以及控制类,
image
image
通过图片分析,Percent Branch Statements(分支语句占比):17.6%,分支语句(if-else、switch、循环等)占可执行语句的比例,该比例适中,说明代码逻辑分支不算过度复杂。Percent Call Statements(方法调用语句占比):94%,方法调用类语句(如函数调用、对象方法调用)占比极高,说明代码高度 “模块化”,通过方法调用组织逻辑,可维护性较好。Name of Most Complex Method(最复杂方法):RequestQueue.processCurrentFloorRequests(),即RequestQueue类的processCurrentFloorRequests方法是代码中逻辑最复杂的方法。Maximum Complexity(最大复杂度):11,代码复杂度通常用 “圈复杂度” 衡量(判断、循环、分支越多,复杂度越高),11 属于中等偏上复杂度,需关注该方法的可读性优化。Line Number of Most Complex Method(最复杂方法的行号):177,定位到该方法在代码中起始于第 177 行,便于针对性优化。Maximum Block Depth(最大代码块深度):5,即代码中嵌套最深的if-else、循环等结构有 5 层嵌套,过深嵌套会降低可读性,需关注。Average Block Depth(平均代码块深度):2.10,整体嵌套深度较合理,仅局部存在深嵌套。Average Complexity(平均复杂度):2.58,所有方法的平均圈复杂度,数值较低,说明多数方法逻辑简单。Percent Lines with Comments(注释行占比):1.7%,注释占比极低,长期维护或团队协作时,会增加代码理解成本,应该关键逻辑处补充注释。
踩坑心得:
首先就是end大小写问题,题目强调不区分大小写,也就是说大小写字母无论怎么组合都可以。其次就是正则表达式的错误使用:在主方法里使用正则表达式来解析输入的数据时由于当时对正则表达式的理解还不够深刻,在解析外部请求的时候,无法将正确的数据给读取进来。这个问题当时困扰了我很久,我也不断地在哪思考问题所在,最后发现我在定义表达式模式的时候少打了一个“,”导致无法正确的去匹配外部请求数据。然后就是关键的电梯运行的逻辑,再提交代码时,会出现运行超时的现象,当上升方向请求运行完了后,外部请求头部的下降的楼层大于上升的楼层时,就会无法清除掉这个外部队列头部请求,导致电梯一直在停靠楼层上下运动,进而运行超时。第二次大作业要注意的是去重。其次没有完全理解题目的电梯运行逻辑,过分关注了"距离优先",而忽略了"方向匹配"这个更重要的判断条件。
改进建议:
降低processCurrentFloorRequests()的复杂度该方法是复杂度最高的部分(最大复杂度 11),主要问题在于循环嵌套过深和递归调用风险,需拆分逻辑并消除递归。
原代码问题分析:存在递归调用processCurrentFloorRequests(currentFloor, currentDir),可能导致栈溢出(尤其请求较多时);内外层循环嵌套 + 条件判断,逻辑堆砌导致复杂度高。
改进方案:拆分方法:将 “处理内部请求” 和 “处理外部请求” 拆分为独立方法;消除递归:用循环替代递归,避免潜在栈溢出;简化逻辑:减少嵌套层级,通过标志位控制流程。
现有代码注释较少,可在关键方法(如 determineDirection、Printans)上添加 Javadoc 注释,说明逻辑意图;在复杂条件处添加行内注释,解释判断目的。
优化命名,方法名 Printans 可改为 runElevatorSimulation,更直观表达 “运行电梯模拟” 的功能;变量名 firstOuter 可改为 firstOuterRequest,增强语义。
总结:
完成本次大作业后,我的代码存在着 “方法复杂度高、代码块嵌套深、功能逻辑耦合” 等问题,减少嵌套深度:通过 “提前返回无效场景”“拆分复杂条件表达式” 等方式,将原代码最大块深度从 5 降低至 3 以内,避免多层嵌套导致的逻辑晦涩(如外部请求处理中拆分楼层匹配、方向匹配条件为独立变量)。命名规范化:优化不直观的命名(如 Printans → runElevatorSimulation、firstOuter → firstOuterRequest),使方法 / 变量语义更清晰,降低理解成本。学到了复杂功能必须拆解为 “小而专” 的模块,后续修改时只需改动对应方法,不会影响整体流程,这是工业级代码可维护性的核心。好的命名和注释是 “写给未来的自己和同事”,能大幅降低后续维护、协作的成本,是专业开发的基本素养。同时加深了对正则表达式的理解,熟悉了这门面向对象的语言的语法,以及java语言的一些原则,拉近了我与java语言的距离。

posted @ 2025-11-22 15:34  code21  阅读(6)  评论(0)    收藏  举报