电梯问题程序-第一次bolg作业-java
一、前言
在现代软件开发中,电梯调度问题是一个经典的算法问题,广泛应用于实际生活中的电梯控制系统。本次博客作业旨在通过Java编程语言实现一个的电梯程序,经过三次代码的迭代,以解决多层建筑中的电梯调度问题。通过这个项目,我们不仅能够深入理解电梯调度算法的核心思想,还能提升Java编程技能,学习如何将算法应用于实际问题中。
本篇博客将详细介绍电梯问题的算法设计思路、代码实现过程以及测试结果。希望通过本次作业,能够为大家提供一个清晰的思路和实用的参考,帮助大家更好地理解和掌握电梯算法的实现方法。让我们一起开始这段编程之旅吧!
二、电梯问题
1. 第一次迭代作业(基础调度逻辑)
1.1 测试样例与问题表现:

1.2 核心问题分析:
在第一次迭代作业中,为了实现电梯调度程序,一共大修改了两次。
(1)队列处理逻辑不完善
现象:当某一队列请求被完全处理时,剩余请求无法正常执行,导致运行超时
根因分析:未建立有效的队列状态监测机制,在队列清空时未及时切换处理另一队列请求
解决方案:增加队列空状态判断模块,优化双队列切换处理逻辑。
如图

(2)方向判断逻辑缺陷
现象:电梯在同层反向请求时拒绝响应(如图)

根因分析:方向判断条件过于严格,仅考虑电梯当前运行方向与请求方向的完全匹配
解决方案:重构方向判断算法,增加同层请求的独立处理分支,优化请求响应优先级
1.3 类结构设计
如图

第一次电梯程序类图如上。其中“Direction”为电梯方向枚举类,“State”为电梯运行状态枚举类,“Passenger”为乘客类,“RequestQueue”为请求队列类,“Elevator”为电梯类,“Controller”为控制类,“Main”为主类。
1.4 代码复杂度分析
如图

(1)基础信息
项目路径: D:\javaText\Blog1
属于Java博客项目,路径版本可能与历史数据(如Blog\或Blog1\)存在迭代关系,需确认是否为同一项目不同模块。
文件命名: (1).txt
命名不规范(应为.java),需检查文件实际内容是否为Java代码。
Checkpoint: Baseline
(2)代码规模与密度
Lines: 249
总代码行数249行,属于中小型文件,但结合Elevator类的复杂度,可能存在职责过重问题。
Statements: 162
可执行语句占比65%(162/249),代码密度适中,但注释严重不足(仅4.4%)。
Method Call Statements: 108
1.方法调用频率较高(占语句数的66.7%),但集中于Elevator.processRequests()(调用56次),需警惕循环依赖或过度耦合。
(3)复杂度与可维护性
分支与条件复杂度
Percent Branch Statements: 27.8%
分支语句(如if-else、switch)占比较高,逻辑复杂度集中在Elevator.processRequests()。
Maximum Complexity: 61
Elevator.processRequests()的圈复杂度(Cyclomatic Complexity)高达61,远超阈值(建议<10),表明该方法存在大量条件分支和循环,维护风险极高。
优化方向:
1.拆分为多个子方法(如请求验证、状态更新、异常处理)。
2.引入状态机或策略模式管理电梯状态变迁。
(4)嵌套深度与可读性
Maximum Block Depth: 7
代码中存在7层嵌套(如多重if-else或循环),显著降低可读性。
Block Depth分布:
深度4-7的语句占比达37.3%((27+31+28+10)/249),需优先重构深层嵌套逻辑。
改进方案:
1.使用卫语句(Guard Clauses)提前返回无效条件。
2.用Stream或函数式编程替代深层循环。
(5)面向对象设计质量
类与方法设计
Classes and Interfaces: 3
包含Elevator和Main类,可能职责划分不合理(如Main类包含24条语句的主逻辑)。
Methods per Class: 4.00
Elevator类有10个方法,但Main类仅有1个方法(main()),设计不均衡。
问题点:
Elevator类承担过多职责(如请求处理、状态管理、接口暴露)。
Main类包含业务逻辑,违背单一职责原则。
重构建议:
拆分Elevator类为ElevatorCore(核心逻辑)、RequestManager(请求管理)、StateMonitor(状态监控)。
将Main类中的业务逻辑迁移到独立服务类中。
(6)方法粒度
Average Statements per Method: 11.00
方法平均长度合理,但Elevator.processRequests()长达68条语句,属于典型“长方法”反模式。
关键问题:
该方法包含56次方法调用,可能隐含高耦合。
圈复杂度和最大深度均为全文件最高,是核心风险点。
(7)注释与文档
Percent Lines with Comments: 4.4%
注释率极低,关键方法(如Elevator.processRequests())缺乏解释,增加维护成本。
改进要求:
1.在复杂逻辑处添加行内注释,说明算法意图。
2.为类和方法添加Javadoc,明确输入输出、副作用及异常。
(8)可视化指标辅助分析
Kiviat Graph
若展示的“Average Complexity”(7.00)与“Max Complexity”(61)差异显著,说明复杂度分布极不均衡,需针对性优化热点方法。
Block Histogram
深度4-7的语句占比过高(柱状图红色部分),验证了嵌套层级过深的问题。
总结与优先级优化
紧急行动
重构Elevator.processRequests(),将其拆分为多个职责单一的子方法(高优先级)。
为所有复杂方法添加注释和文档(紧急)。
中期优化
使用设计模式(如状态模式、观察者模式)解耦Elevator类职责。
减少Main类的业务逻辑,将其委托给服务类。
流程改进
在代码审查中强制要求注释率和复杂度阈值。
引入静态分析工具(如SonarQube)持续监控代码质量。
2.第二次迭代作业(异常处理优化)
2.1 测试样例与运行结果


2.2 关键问题突破
在第二次迭代作业中,为了实现电梯调度程序,一共大修改了两次。
(1)非法数据去除位置
现象:未理解题目意思,非法数据的位置是在已经将请求数据添加到队列中,当程序检测到非法数据时,立即停止程序,导致答案错误。
解决方案:改为在输入过程中检测到非法数据,则跳过该数据。
(2)数据结构应用误区Linkedlist
问题根源:对LinkedList特性理解不足导致数据遍历异常
技术突破:
1.采用迭代器模式实现安全遍历
2.建立请求哈希表实现O(1)复杂度去重
3.开发请求状态追踪系统,确保数据一致性
2.3 类结构设计
如图

第二次电梯程序类图如上。其中“Direction”为电梯方向枚举类,“State”为电梯运行状态枚举类,“Passenger”为乘客类,“RequestQueue”为请求队列类,“Elevator”为电梯类,“Controller”为控制类,“Main”为主类。
2.4 代码复杂度分析
如图

(1)基础信息
项目路径: D:\javaText\Blog1
与文件(1).txt属于同一项目路径,可能为同一系统的不同模块或迭代版本。
文件命名: (2).txt
命名仍不规范(应为.java),需确认文件实际内容是否为Java代码。
Checkpoint: Baseline
基准版本标识,可能与(1).txt为并行模块或功能扩展。
(2)代码规模与密度
Lines: 337
总代码行数增至337行,规模中等,但需警惕模块膨胀风险。
Statements: 228
可执行语句占比67.7%(228/337),代码密度合理,但注释率仅5.3%,仍远低于行业标准。
Method Call Statements: 212
方法调用频率极高(占语句数的93%),且集中于Controller.processRequests()(调用171次),可能隐含以下问题:
循环依赖:如Controller与RequestQueue互相调用。
过度碎片化:方法粒度过小导致调用链冗长。
(3)复杂度与可维护性
分支与条件复杂度
Percent Branch Statements: 23.2%
分支语句占比低于(1).txt(27.8%),但Controller.processRequests()的圈复杂度高达59,表明其逻辑复杂度仍极高。
优化方向:
使用责任链模式拆分请求处理流程(如验证→路由→执行)。
引入事件驱动机制解耦请求处理逻辑。
(4)嵌套深度与可读性
Maximum Block Depth: 7
与(1).txt相同,深层嵌套问题未改善。
Block Depth分布:深度5-7的语句占比达20.5%(32+29+7=68/337),需优先重构。
改进方案:
使用Optional或空对象模式替代null检查,减少条件嵌套。
用策略模式封装不同深度的业务逻辑。
(5)面向对象设计质量
类与方法设计
Classes and Interfaces: 7
新增Controller、RequestQueue、ExternalRequest等类,职责划分更细,但需验证以下问题:
内聚性:RequestQueue仅提供简单队列操作,是否应合并到Controller?
接口抽象:ExternalRequest仅为数据载体,未定义接口,可能限制扩展性。
Methods per Class: 4.43
Controller类有8个方法,但大部分为Getter/Setter,核心逻辑集中在processRequests(),设计失衡。
问题点:
Controller类承担核心业务逻辑,但未通过接口隔离实现细节。
RequestQueue的线程安全性未体现(如getQueueInstance()是否为单例?)。
方法粒度
Average Statements per Method: 5.68
方法平均长度较优,但Controller.processRequests()长达97条语句,远超平均值,属于典型“长方法”反模式。
关键问题:
该方法调用171次其他方法,可能隐含高耦合。
最大嵌套深度7,圈复杂度59,维护风险极高。
(6)注释与文档
Percent Lines with Comments: 5.3%
注释率略有提升(对比(1).txt的4.4%),但仍严重不足,关键方法(如Controller.processRequests())缺乏解释。
改进要求:
为复杂业务规则(如请求优先级、超时机制)添加注释。
使用Javadoc描述类职责和方法契约。
(7)可视化指标辅助分析
Kiviat Graph
若“Average Complexity”(3.52)与“Max Complexity”(59)差异显著,表明复杂度分布严重不均衡,需针对性优化热点方法。
Block Histogram
深度5-7的语句占比高,验证了嵌套层级过深的问题。
(8)总结与优先级优化
紧急行动
重构Controller.processRequests(),按职责拆分为validateRequest()、scheduleRequest()、executeRequest()等子方法(高优先级)。
为Controller和RequestQueue添加线程安全注解(如@ThreadSafe)或文档说明(紧急)。
中期优化
引入接口抽象(如RequestHandler),解耦Controller与RequestQueue。
使用工厂模式统一管理Elevator和RequestQueue实例化。
流程改进
在持续集成(CI)中集成代码复杂度检测,阻断圈复杂度>15的方法提交。
针对Controller.processRequests()设计负载测试,验证高并发场景下的稳定性。
3.第三次迭代(高级调度策略)
3.1 测试验证结果
如图



3.2 难点攻关记录
在第三次迭代作业中,为了实现电梯调度程序,一共大修改了两次。
(1)需求理解偏差
误区:混淆请求方向与目标楼层的关系
修正方案:
1.建立请求元数据解析器(方向、目标层、时间戳)
2.开发方向决策矩阵,实现N向调度
3.增加请求验证测试用例集
(2)边界条件处理
现象:已知的测试样例都可以通过,但是第二个和第三个测试点一直无法通过,于是试着输入单个请求,出现了运行超时。
解决方案:重新修改代码结构,优化单个请求处理逻辑。
3.3 类结构设计
如图

第三次电梯程序类图如上。其中“Direction”为电梯方向枚举类,“State”为电梯运行状态枚举类,“ExternalRequest”为外部乘客请求类,“RequestQueue”为请求队列类,“Elevator”为电梯类,“Controller”为控制类,“Main”为主类。
3.3 类结构设计
如图

(1)复杂度集中点
Controller.processRequests()
圈复杂度52:仍远高于安全阈值(建议<15),但较前版(59)有所降低,可能已进行部分重构。
调用次数174:方法依赖链极长,耦合度高。
嵌套深度7:深层逻辑未彻底解决(如电梯移动逻辑、门状态判断)。
Controller.removeRequest()
圈复杂度10:需检查条件分支是否可简化(如用Map替代多重if-else)。
(2)类设计失衡
Controller类:包含11个方法,承担电梯控制、请求处理、日志打印等多重职责,违背单一职责原则。
Passenger类:多个构造器(Passenger()重复3次),可能由重载引起,需统一为Builder模式。
(3)注释与可读性
注释率5.0%:关键算法(如电梯调度策略)缺乏解释,如Passenger.getDirection()中的方向判断逻辑。
(4)代码膨胀迹象
Lines增至363:较(2).txt增加26行,但功能扩展有限(新增move()、printMove()等方法),警惕“代码蠕变”。
(5)优先级优化建议
- 紧急重构:Controller.processRequests()
拆分策略
状态分离:将电梯移动逻辑抽离为ElevatorMovementService(含move()、checkCollision())。
事件解耦:用观察者模式实现门状态变化通知(DoorOpenEvent/DoorCloseEvent)。
日志隔离:将printMove()迁移到独立MovementLogger类,避免业务逻辑与IO耦合。
复杂度控制:为目标子方法设置圈复杂度阈值(如<10),通过单元测试验证路径覆盖。 - 类职责优化
Controller类瘦身
拆分为三个组件:
RequestProcessor:处理请求队列(processRequests、removeRequest)。
ElevatorOperator:控制电梯行为(move、openDoor)。
AuditService:处理日志与状态监控(printMove)。 - 嵌套深度治理
深度>3的逻辑(占比14.3%):
替换策略:
用Java Stream API替代for循环+条件嵌套(如过滤无效请求)。
用责任链模式处理多层条件判断(如电梯移动方向决策链)。
工具辅助:启用IDE的Replace Conditional with Polymorphism自动重构功能。
三、迭代对比
指标 (1).txt (2).txt (3).txt 趋势分析
代码规模
Lines 249 337 (+35.3%) 363 (+7.7%) 持续膨胀,需警惕模块拆分
Statements 162 228 (+40.7%) 246 (+7.9%) 功能扩展导致可执行代码增加
复杂度
Max Complexity 61 59 (-3.3%) 52 (-11.9%) 逐步优化,但绝对值仍高风险
Avg Complexity 7.00 3.52 (-49.7%) 3.00 (-14.8%) 整体复杂度下降显著
可维护性
Percent Comments 4.4% 5.3% (+20.5%) 5.0% (-5.7%) 注释率停滞,需强制规范
Avg Statements/Method 11.00 5.68 (-48.4%) 4.63 (-18.5%) 方法粒度持续优化
嵌套深度
Max Block Depth 7 7 7 深层嵌套未根治
Depth≥5 语句占比 37.3% 20.5% (-45%) 14.3% (-30%) 显著改善,但仍有优化空间
关键改进与遗留问题
- 正向优化趋势
复杂度控制
最大复杂度从61→52:通过拆分Controller.processRequests()方法(如(3).txt中新增move()、printMove()),但未彻底解耦核心逻辑。
平均复杂度从7.0→3.0:表明非热点方法(如Getter/Setter)占比增加,核心逻辑仍需优化。
方法粒度优化
方法平均长度从11→4.63行:符合“短方法”原则,但部分方法过度碎片化(如Controller类多个1行方法)。
嵌套层级改善
深度≥5的语句占比下降63%:通过卫语句、Stream API替代部分深层逻辑。 - 遗留风险点
注释率停滞(~5%)
缺乏强制规范,关键算法(如电梯调度策略)仍无文档。
类职责失衡
Controller类在(3).txt中仍承担请求处理、电梯操作、日志打印三重职责。
代码膨胀
总行数增长45.8%(249→363),但功能扩展有限(如新增Passenger类仅含简单属性)。 - 核心方法分析:Controller.processRequests()
版本 圈复杂度 语句数 调用次数 优化措施
(1).txt 61 68 56 -
(2).txt 59 97 171 拆分为removeRequest()等子方法
(3).txt 52 83 174 新增move(),但耦合未彻底解决
问题:调用次数不降反增(56→174),表明拆分子方法后调用链更
四、心路历程
刚开始看到这道题的时候,我是绝望的,这不是我写得出来的题目。但是当我听到同学们都在讨论这道题,并给出这道题的想法时,大大刺激了我对这道题的兴趣。于是我也开始参与讨论,并对算法进行构想。经过我不懈的努力,还有老师提供的补充数据以及补充测试用例,以及同学的帮助,最终,我终于在截止前的几分钟完成了这道题。
第一次迭代的时候,虽然电梯程序有一些不足,但我在后面的第二、第三次迭代中,充分吸取了第一次的经验,大胆思考,小心验证,比较顺利地通过了第二、第三次的题目集。虽然第三次的题目因为理解错误导致我卡了好一会儿,但最终还是通过了。
五、感悟
在面对困难的时候,我们应该坚持不懈,努力解决问题,而不是自怨自艾。在不懈的努力中,总会成功。通过这次项目,我深刻体会到了团队合作的重要性,以及不断学习和改进的重要性。希望这次经历能够激励我在未来的编程道路上继续前进,不断挑战自我,提升自己的编程技能。

浙公网安备 33010602011771号