面向对象程序设计-电梯调度问题-总结

一、前言
这三次题集围绕电梯调度展开,体现清晰的递进学习方法。题集一作为基础入门,帮我提高代码编写能力,正则表达式练习强化了基础逻辑,后续接触点与线的类设计,让我初步了解面向对象编程,虽对类,对象概念懵懂,但开启了思维转变。
题集二聚焦面向对象思维强化,雨刷题让我跳出面向过程的固有思路,将控制杆、刻度盘、雨刷拆分为独立类,切实理解单一职责原则。
题集三,销售步枪题锻炼了类的功能拆分能力,蒙特卡洛求圆周率题则提升了算法设计思路,学会了综合运用知识解决复杂问题。
这些积累恰好能对应电梯调度这类场景:类封装知识能规范电梯、乘客请求等实体的属性与方法;拆分电梯状态管理、请求处理、调度算法等独立模块;建模与算法思路能优化调度策略,边界处理能力则可应对楼层限制,保障系统高效可靠。

二、第一次代码
1. 设计分析
代码类的关系设计图:
image
类间关系说明
依赖关系:Request类依赖RequestType和Direction枚举,用于限定请求的类型和方向取值;
关联关系:Elevator类关联FloorRange(依赖其进行楼层校验)和Queue(存储待处理请求);
组合关系:ElevatorSimulation作为主类,组合Elevator和FloorRange实例,协调整体流程。

使用SourceMonitor对代码进行分析:
image

指标名称 数值 解读与分析
代码总行数 216 行 代码量适中,无冗余,符合中小型工具类程序的规模
有效语句数 84 条 语句密度合理,说明代码逻辑紧凑,无过多空行或无效代码
分支语句占比 20.2% 分支占比适中,主要集中在调度算法(findNextTarget())和输入解析(main()),逻辑判断清晰,无过度嵌套
注释率 18.1% 注释率偏低,核心调度方法,缺乏详细说明,可能影响后续维护
平均每个类方法数 3.5 个 类的方法数量适中,符合 “单一职责”,无大类或方法冗余的问题
平均每个方法语句数 11.29 条 方法粒度合理,无超长篇方法,便于调试和修改
最大方法复杂度 6(main()) main()方法因包含输入解析、循环处理等逻辑,复杂度略高,但仍在可接受范围,未出现过度复杂的逻辑嵌套

代码结构与复杂度:代码总行数 216 行,包含 84 条有效语句,规模适中,无冗余代码。分支语句占比 20.2%,主要集中在调度算法,逻辑判断清晰但存在少量嵌套。平均每个类 3.5 个方法、每个方法 11.29 条语句,方法粒度合理,无超长篇方法;最大方法复杂度为 6(ElevatorSimulation.main()),虽在可接受范围,但主方法因集成多逻辑导致复杂度略高。
代码正确性:从报表及类图设计来看,未出现明显逻辑冲突,请求校验、方向判断、调度流程均符合电梯运行基本规则,无明显语法或逻辑错误,可正常完成单部电梯的调度模拟。

2.踩坑心得与改进建议:
1.主方法职责过重:ElevatorSimulation类 方法同时承担输入读取、请求解析、组件初始化等功能,复杂度较高,不利于后续维护;
违背 “单一职责原则”,Elevator类同时承担 “业务逻辑(调度)” 和 “工具逻辑(校验)”,导致职责混乱、修改成本高。类设计的核心是 “各司其职”,复杂问题需先按功能拆分模块,再逐个实现。工具类与业务类的分离,能大幅降低修改成本,这也是后续代码能快速迭代优化的基础。
2.调度算法逻辑缺陷,未实现 “同向优先” 导致效率极低
初期采用 “先来先服务(FCFS)” 算法,即按请求输入顺序处理,提交后测试时出现电梯频繁往返的问题。
未贴合实际电梯运行逻辑,FCFS 算法忽略请求方向与电梯当前运行方向的一致性,导致无效往返,调度效率低下。
应该使用 “同向优先” 策略(LOOK 算法简化版),核心流程调整如下:
原流程:请求队列→按输入顺序取请求→运行至目标楼层
新流程:请求队列→判断电梯当前方向→筛选同向请求→找最近目标→运行→无同向则转向
3.原设计思路问题很大,未能理解题目意思

  1. 输入范围类关于输入最大楼层,最小楼层,限制电梯的运行范围
  2. 运行状态类关于运行方向,电梯向上或电梯向下或停止,标注电梯运行状态,以及电梯运行状态的转变。
  3. 楼层输入类用队列进行存储,将全部按照要求所输入的楼层依次进行存储,不消除重复数据,相同数据只要不相邻可以依次存入,同时存储方向或方向的转变。
  4. 电梯运行类用于电梯到达某一层时,在队列中取出删除对应楼层,并调用输出类进行输出楼层。
  5. 电梯对比类,在队列中进行查找,若方向向上首先找楼层更大的进行输出,当之后队列中无更大楼层,才调转方向,运行向下,寻找最接近的楼层向下运行输出。运行向下情况类似。当队列中为空,或无电梯楼层时显示停止状态。
  6. 楼层输出类,若无要求,从第一层开始输出,用于将经过某楼层输出,直接输出对应楼层及方向。或者是到达某楼层输出,当到达某楼层时,按要求输出。
  7. 主类main用于依次调用各类进行运行电梯。

算法选择有问题,不应该使用队列一次性存储所有输入数据,然后再进行调度。
所以算法设计必须贴合实际场景,避免题目意思没理解清楚,导致与实际不符,电梯调度的核心是 “减少无效移动”,而 “同向优先” 正是基于此场景的优化。编写复杂业务代码前,应先梳理实际业务逻辑,再转化为流程图,最后编码实现。

三、第二次代码
1. 设计分析
代码类的关系设计图:
image

核心元素 类型 核心职责
Direction 枚举 定义电梯运行方向:UP(上行)、DOWN(下行),无停止状态枚举
Elevator 核心业务类 封装电梯运行范围(minFloor/maxFloor)、当前状态(楼层 / 方向)、三类请求列表(内部 / 外部上行 / 外部下行),实现运行与请求处理逻辑
Main 主类 处理用户输入(楼层范围、请求)、初始化电梯实例、触发电梯运行

依赖关系:Elevator类依赖Direction枚举,用于限定电梯运行方向和外部请求方向的取值范围;
组合关系:Main类作为主类,组合Elevator实例,负责初始化电梯、处理输入并触发电梯运行,协调整体流程;
无独立数据封装类,请求相关信息直接通过List分类存储,未进行对象化封装。

使用SourceMonitor对代码进行分析:
image
image

指标名称 数值 解读与分析
代码总行数 154 行 代码量精简,但核心逻辑存在硬编码冗余,整体规模符合小型程序定位,但功能通用性不足
有效语句数 103 条 语句密度较高,部分方法,因集成多逻辑导致语句集中,冗余度高
分支语句占比 25.2% 分支主要集中在processUp()和processDownToMin()方法,逻辑判断针对性过强,缺乏通用性
注释率 0.6% 几乎无有效注释,核心硬编码逻辑,无任何说明,后续维护需重新梳理全部逻辑
平均每个类方法数 2.67 个 共 3 个类(含 2 个核心类 + 1 个枚举),Elevator类含 7 个方法,承担全部核心职责,职责分配不均
平均每个方法语句数 10.25 条 方法粒度基本合理,但processUp()方法集成楼层移动、请求判断、停靠逻辑,语句集中导致复杂度升高
最大方法复杂度 11(Elevator.processUp()) 该方法包含循环、多条件分支及集合操作,因硬编码判断和逻辑集成,复杂度显著高于其他方法,易出现逻辑漏洞

代码结构与复杂度
代码总行数 154 行,含 103 条有效语句,规模精简但逻辑设计缺陷明显。分支语句占比 25.2%,集中在 processUp () 和 processDownToMin () 的请求处理逻辑,判断条件针对性过强。Elevator 类包揽请求存储、调度算法、运行控制、停靠判断等全部核心职责,违背单一职责原则;processUp () 方法复杂度达 11,因逻辑过度集成导致调试修改难度高。

2.踩坑心得与改进建议
1.调度算法僵化:采用 “上行到底→下行到底” 固定流程,未考虑请求方向匹配度,导致大量无效移动,未把握电梯调度 “减少无效移动” 的核心目标,忽略 “同向请求优先处理” 逻辑。改进建议:重构为 “同向优先” 策略(LOOK 算法简化版),新增 Direction.STOP 枚举值;循环筛选同向请求(外部同方向 + 内部任意方向),找最近目标楼层运行;无同向请求则转向或转为 STOP 状态。
2.请求存储结构不合理:拆分为三个独立 List 存储请求,调度时需跨列表筛选,逻辑繁琐且扩展性差,未对请求统一对象化封装,多列表关联逻辑增加处理成本。应该:新增 Request 类封装请求信息,用单个列表存储所有请求,通过属性区分类型与方向。
3.忽视 “输入合法性反馈” 的用户需求,未考虑用户对输入结果的知情权,导致代码健壮性和用户体验双差。
4. 类设计违背单一职责原则,Elevator 类职责过重
Elevator 类同时负责请求存储、校验、调度算法、运行控制、停靠判断,含 7 个方法,耦合度高。应该调整调度算法可能影响停靠逻辑,维护成本高。未拆分模块,核心逻辑集中,违背单一职责原则,导致耦合高、可维护性差。
改进建议:拆分 Elevator 职责,新增工具类与数据封装类;新增 RequestManager 类负责请求存储、去重、筛选;Elevator 仅保留状态管理(当前楼层、方向)与运行控制,依赖 FloorValidator 和 RequestManager;拆分后 Elevator 依赖二者,RequestManager 依赖 Request 类,职责清晰,耦合降低。

四、第三次代码
1. 设计分析
代码类的关系设计图:
image

核心元素 类型 核心职责
Direction 枚举 定义电梯运行方向:UP(上行)、DOWN(下行)、STOP(停止),补充停止状态枚举
Request 实体类 封装请求信息:类型(内部 / 外部)、目标楼层、请求方向(内部请求为 STOP)
FloorValidator 工具类 校验目标楼层是否在电梯运行范围内,提供 isValidFloor () 方法
RequestManager 工具类 管理请求的存储、去重、筛选,提供添加请求、获取同向请求等方法
Elevator 核心业务类 封装电梯当前状态(楼层 / 方向),依赖 RequestManager 和 FloorValidator 实现运行、停靠逻辑
Main 主类 处理用户输入、初始化各组件(Elevator、RequestManager 等)、触发电梯调度流程

依赖关系:Elevator类依赖RequestManager和FloorValidator,用于请求管理和楼层校验;RequestManager依赖Request类,用于封装请求数据;
组合关系:Main类组合Elevator、RequestManager、FloorValidator实例,协调整体流程;
数据封装:请求信息统一封装为Request对象,解决了之前分类存储的混乱问题。

使用SourceMonitor对代码进行分析:
image

指标名称 数值 解读与分析
代码总行数 220 行 代码量略有增加,因拆分类和封装请求导致,但逻辑更清晰,通用性提升
有效语句数 120 条 语句密度适中,类拆分后逻辑分散,冗余度降低
分支语句占比 22.0% 分支集中在Elevator.processSameDir()和RequestManager.getSameDirRequests(),逻辑更通用
注释率 12.3% 核心方法(如调度逻辑、请求筛选)添加了基础注释,后续维护成本降低,但关键细节仍需补充
平均每个类方法数 3.2 个 共 5 个类,各分类职责均衡,Elevator类含 6 个方法,不再包揽全部核心工作
平均每个方法语句数 9.5 条 方法粒度更合理,逻辑分散后单个方法语句减少,复杂度降低
最大方法复杂度 8(Elevator.processSameDir()) 该方法包含同向请求筛选和楼层移动逻辑,复杂度较之前降低,仍需优化筛选效率

代码结构与复杂度
代码总行数 220 行,含 120 条有效语句,因拆分类和封装请求代码量增加,但逻辑更合理。分支语句占比 22.0%,集中在调度与请求筛选方法,判断条件更通用。类职责划分清晰(Elevator 管状态运行、RequestManager 管请求、FloorValidator 管校验),符合单一职责原则;最大方法复杂度降至 8,调试难度降低。语法无错可稳定运行,调度适配多数场景,但请求量大时筛选效率略低。

2.踩坑心得与改进建议
1.类拆分后依赖关系混乱拆分出RequestManager和FloorValidator后,因初始化顺序错误,导致电梯调用请求方法时出现空指针。
改进建议:按 “工具类→管理类→核心业务类” 的顺序初始化组件,在Main类中先创建FloorValidator和RequestManager,再传入Elevator构造方法。
2.同向请求筛选效率低RequestManager.getSameDirRequests()通过遍历列表筛选同向请求,边界楼层方向处理漏判电梯到达最高 / 最低楼层时,未强制切换方向,导致偶尔出现 “在最高楼层仍尝试上行” 的逻辑漏洞。
输入解析仍有遗漏外部请求输入格式为 “<楼层,方向>” 时,若楼层带空格,解析会失败。

五、总结
这三次题集和电梯代码的迭代,是我学语言代码以来解决问题最复杂的一段经历。最开始写第一次代码时,主方法里堆了输入、解析、初始化所有逻辑,改个楼层校验得扒半段代码,才懂单一职责不是仅仅拆开来,改规则只动一个类,那瞬间是真的通透。
第二次代码硬编码通过测试样例,换个测试样例直接失效,调度让电梯白跑半栋楼,才明白算法得贴实际场景,不是随便堆流程。第三次拆分出后,因为初始化顺序错碰上空指针,调试到半夜才反应过来,类多了更要理清楚依赖,不能瞎堆。
现在再碰复杂问题,我不会直接写代码了,先完全读懂题目意思,拆模块、想清楚谁管啥,再慢慢填逻辑。原来写程序不是跑起来就行,不仅仅是通过测试样例就行,得让代码好改、能用,这堆坑踩下来,才真理解面向对象思想。

posted @ 2025-11-22 20:11  Lazy0811  阅读(0)  评论(0)    收藏  举报