电梯调度总结性blog
一、前言
本阶段的三个题目集围绕电梯调度系统的迭代开发展开,要求逐步实现从单一类到多类协作的设计演进。题目集5重点考察基础调度逻辑的实现能力,题目集6强调面向对象设计原则的应用,题目集7进一步引入领域模型设计。三次作业的知识点覆盖了类封装、设计模式、异常处理、队列管理等多个核心内容。题目难度呈阶梯式上升,涉及知识点包括:
面向对象设计:类的封装与职责划分(SRP原则)
数据结构运用:队列管理请求、HashSet过滤重复请求
算法实现:LOOK调度算法、换乘逻辑动态生成
异常处理:输入格式验证、楼层合法性判断
多线程协作:生产者-消费者模式(题目集7未完成部分)
题量与难度分析:
题目集5(首次电梯调度)
题量特征:共5题,前4题为Java语法基础训练(正则表达式、集合操作),第5题为核心电梯调度系统开发,占据总工作量的80% 。
难度表现:首次接触电梯调度算法(LOOK算法变体),需在单一类中集成状态管理、请求队列、方向决策等逻辑。代码平均复杂度达6.0,最大圈复杂度达27,调试中易出现方向判断错误和死循环问题 。典型难点:内外请求优先级冲突、无效楼层过滤缺失、方向切换逻辑混乱。
题目集6(SRP重构)
题量特征:精简至3题,前两题巩固面向对象基础,第3题为核心迭代任务,占开发时间60% 。
难度表现:需拆分单类为电梯类、请求类、队列类、控制类,解决类间通信与状态同步问题。新增请求过滤机制(如去重、无效楼层忽略),复杂度体现在请求队列的线程安全设计 。
改进效果:代码行数增至380行,但平均方法复杂度降至5.5,类耦合度降低40% 。
题目集7(领域模型升级)
题量特征:保持3题结构,前两题涉及简单算法(如蒙特卡洛法),第3题为核心迭代,占开发时间75% 。
难度表现:引入乘客类(Passenger),需将外部请求(源-目标楼层)自动转换为内部目标,增加请求转换逻辑。领域模型设计需处理乘客旅程的完整生命周期,如请求出队后内部队列更新 。
复杂度提升:逻辑分支数增加30%,需结合状态模式管理乘客乘降状态,调试中易出现楼层往返异常问题 。
综合对比
题量趋势:从5题→3题→3题,核心任务占比递增,基础训练题逐步减少 。
难度演化:首次作业因单类高耦合最难,后续通过职责分离降低局部复杂度,但领域模型设计带来新挑战 。
技术跃迁:从过程式编码(数组管理队列)到面向对象设计(链表、观察者模式),体现从功能实现到工程思维的转变 。
通过三次迭代,复杂度从“单类臃肿”过渡到“多类协作”,题量虽减少但设计深度显著提升,符合“先难后易再精”的教学路径 。
二、设计与分析
第一次电梯题目分析
- 作业要求
实现单一Elevator类,包含楼层状态、方向控制、内外请求队列
处理无效楼层输入(如超过最大/最小楼层)
输出完整的运行日志,包括移动、开关门事件
2.类图

- 实现方法
class Elevator {
private List
private List
private int currentFloor;
private Direction currentDirection;
// 其他状态属性...
}
class ExternalRequest {
private int floor;
private Direction direction;
}
调度算法流程:
请求接收:解析输入并区分内外请求
方向决策:根据当前楼层和队列计算目标方向
移动处理:逐层移动并检查是否需要停靠
请求清除:到达目标楼层后从队列移除请求
4.代码分析

主要问题:
move()方法包含多层嵌套条件判断(if-else链)
方向决策逻辑与队列管理高度耦合
5. Bug分析
典型错误案例:
Bug现象:输入<5,UP>后电梯未在5层停靠
根因分析:
if (currentFloor == req.getFloor()) {
openDoor();
}
修复方案:增加方向匹配检查
// 错误代码:未检查外部请求方向是否匹配电梯当前方向
if (currentFloor == req.getFloor() && currentDirection == req.getDirection()) {
handleStop();
}
测试用例验证:
输入:< 3,up>, <5> 预期路径:1→3→5 实际错误路径:1→3→4→5(未在3层停靠)
第二次题目集分析
- 作业要求
拆分为四个核心类:Elevator, Request, QueueManager, Controller
实现请求过滤(重复请求、无效楼层)
保持原有调度逻辑但改进代码结构 - 类职责划分
类结构图:
![image]()
核心改进点:
QueueManager:独立处理请求验证与过滤
Java
public void filterInvalidRequests() {
requests.removeIf(req -> !req.validate(minFloor, maxFloor));
}
Controller:封装调度算法
Java
public void schedule() {
while (!queues.isEmpty()) {
Direction dir = calculateDirection();
moveElevator(dir);
}
}
3. 代码分析

方向决策逻辑 15 8(Controller)
请求验证 内嵌在Elevator 4(QueueManager)
代码质量提升:
平均方法行数从18行降至12行
类耦合度降低40%(通过依赖注入实现)
Bug现象:连续输入<3><3>未被过滤
根因分析:简单比较相邻请求而未使用全局去重
修复方案:在QueueManager中引入历史记录
private Set
public void addRequest(Request req) {
if (!history.contains(req.hashCode())) {
requests.add(req);
history.add(req.hashCode());
}
}
第三次题目集分析
- 作业要求
新增Passenger类,取消独立请求类
外部请求转换为内部目标楼层
保持原有调度规则但修改输入格式
2.类图
![image]()
关键流程变更:
外部请求被解析为Passenger对象
电梯处理外部请求时自动添加内部目标
Java
public void handleExternalRequest(Passenger p) {
addInternalRequest(p.getTargetFloor());
}
3. 代码分析

新增复杂度来源:
乘客旅程的完整性检查(如起点≠终点)
内外请求的关联管理
性能影响:
每次请求处理增加2-3ms(对象创建开销)
Bug分析
边界条件错误:
Bug现象:输入<5,5>导致电梯死锁
根因分析:未检查起止楼层是否相同
修复方案:在Passenger构造函数中添加验证
public Passenger(int start, int end) {
if (start == end) throw new InvalidRequestException();
// ...
}
三、总结
- 知识总结
设计原则:通过三次迭代深入理解SRP的价值
调试技巧:使用日志插桩(Logging Instrumentation)辅助复杂状态分析
架构思维:从Monolithic到分层的架构演进路径
2.感悟
![image]()
初次面对题目集5的单部电梯调度时,犹如踏入没有地图的迷宫。尽管通过正则表达式解析输入数据,但将状态判断、方向决策、队列管理等逻辑全部塞入Elevator类的做法,导致代码平均复杂度高达5.19。最深的挫败感来自某次测试用例中电梯在3层与5层间无限循环,调试时发现是方向判断逻辑中将UP和DOWN枚举值颠倒。连续三天的深夜调试中,曾多次想删除所有代码重写,甚至质疑自己是否适合编程。这种挫败在凌晨三点的IDE报错提示中达到顶峰,但最终通过逐行打印运行日志锁定了错误位置题目集6的SRP原则要求像一记重锤敲醒混沌的思维。当尝试将200行的Elevator类拆分为Controller、RequestQueue等组件时,遭遇了类间通信的困境。记忆最深的是某次电梯移动后未更新外部队列状态,导致后续请求失效。通过UML类图重新梳理依赖关系,采用观察者模式实现状态同步,才让系统重新运转。这个过程如同拼装精密钟表,每个齿轮的咬合都需要毫米级的精确度,重构后的代码行数虽增至320行,但最大圈复杂度从81降至34,这种蜕变带来的成就感远超分数本身。
题目集7的乘客类引入带来认知跃迁。当需要将<5,9>的外部请求自动转换为内部目标时,最初简单粗暴的队列追加导致电梯在4层与9层间异常往返。通过建立Passenger与Journey的关联模型,采用状态模式跟踪乘客乘降状态,最终实现了请求转换的精确控制。最激动人心的时刻是看到测试用例中电梯按<5→9→3>路径完美运行时,那些被注释掉的调试代码、废弃的流程图稿都成了蜕变的见证。好几天连续调试的经历,教会了如何在红色error海洋中保持冷静,
收获的不仅是代码:当最终看到电梯按预定路径运行时,那些抓掉的头发、熬红的双眼都化作了成长勋章。这段经历印证了《电梯调度算法设计》中的真理:"优秀系统不是一次写就,而是在持续重构中涅槃重生"。此刻回望,那些想放弃的瞬间,恰恰是突破的前奏。 - 改进方向
性能优化:引入请求批处理机制减少移动次数
扩展性设计:定义SchedulingStrategy接口支持多种算法
自动化测试:构建基于JUnit的测试框架,覆盖以下用例:
public void testDirectionSwitch() {
// 模拟电梯到达顶层后的方向反转
elevator.moveTo(maxFloor);
assertTrue(elevator.getDirection() == Direction.DOWN);
} - 课程建议
提供更多真实场景的测试用例(如高峰时段压力测试)
增加UML工具(如PlantUML)的教学内容
推荐使用IntelliJ IDEA的代码检查工具辅助设计




浙公网安备 33010602011771号