三次单部电梯调度程序设计总结
前言
本次题目集包含三道递进式的单部电梯调度程序设计题,是面向对象编程思想与设计原则的典型实战案例。三道题目围绕电梯调度的核心逻辑,从单一类的臃肿设计逐步迭代为符合单一职责原则(SRP) 的模块化设计,难度呈阶梯式上升,覆盖的知识点与题量特征如下:
知识点覆盖:核心包括面向对象的类设计与封装、队列的增删改查操作、电梯调度的同向优先算法、输入校验与无效请求过滤、状态管理(停止 / 移动 / 开门 / 关门)、单一职责原则的落地实践;延伸知识点包括设计模式的初步应用(如状态模式、策略模式)、数据去重与异常处理、代码模块化与解耦。
题量特征:三道题目均为单部电梯调度的迭代设计,输入输出格式基本一致,但类结构与业务逻辑的复杂度逐步提升 —— 从 “单类包揽所有职责” 到 “拆分请求类 / 队列类 / 控制类”,再到 “引入乘客类并调整外部请求逻辑”,核心调度算法不变,但代码的可维护性与扩展性要求显著提高。
难度梯度:第一题侧重功能实现,只需完成电梯的基础调度与输入输出;第二题侧重设计原则,要求拆分类职责,解决 “电梯类职责过多” 的问题,并处理重复请求与无效楼层;第三题侧重需求迭代,新增乘客类、调整外部请求格式,要求在保持 SRP 的前提下适配新的业务逻辑,是对类设计与逻辑衔接的综合考察。
题目一:单一电梯类的基础实现
设计思路
题目一未对类结构做限制,核心思路是用一个Elevator类包揽所有职责:包含电梯的属性(最小 / 最大楼层、当前楼层、运行方向、运行状态)、请求队列(内部请求队列、外部上行 / 下行队列),以及方法(请求入队、调度运行、输入处理、输出打印)。
核心算法与心得
调度算法的核心是同向优先:电梯向某个方向移动时,优先处理该方向的所有请求(内部 + 外部),处理完毕后再切换方向。例如,电梯上行时,会依次处理路径上的外部上行请求和内部请求,直到无同向请求后,再处理下行请求。
心得:单一类设计的优势是快速实现功能,无需考虑类间的衔接;但劣势极为明显 —— 代码臃肿、职责混杂,如果要修改输入格式或调度规则,需在同一个类中大幅改动,违反 “开闭原则”。例如,新增 “重复请求过滤” 功能时,需在addRequest方法中加入大量判断,导致方法逻辑更加复杂。
Metrics Details For File 'Main.java'
Parameter Value
========= =====
Project Directory D:\eclipse-workplace\experiment1\src\experiment1
Project Name 123
Checkpoint Name Baseline
File Name Main.java
Lines 414
Statements 116
Percent Branch Statements 12.1
Method Call Statements 92
Percent Lines with Comments 47.6
Classes and Interfaces 2
Methods per Class 5.00
Average Statements per Method 10.10
Line Number of Most Complex Method 49
Name of Most Complex Method ElevatorController.handleRequests()
Maximum Complexity 11
Line Number of Deepest Block 198
Maximum Block Depth 9+
Average Block Depth 4.15
Average Complexity 4.00
Most Complex Methods in 2 Class(es): Complexity, Statements, Max Depth, Calls
ElevatorController.ElevatorController() 1, 2, 2, 0
ElevatorController.handleRequests() 11, 21, 5, 9
ElevatorController.processDownMovement() 1, 3, 2, 3
ElevatorController.processMovement() 1, 1, 2, 3
ElevatorController.processUpMovement() 1, 3, 2, 3
Main.main() 9, 20, 6, 17
Block Depth Statements
0 4
1 11
2 29
3 12
4 10
5 21
6 6
7 5
8 2
9+ 16

题目二:遵循 SRP 的类拆分设计
设计思路
题目二要求解决电梯类职责过多的问题,核心是按职责拆分类,必须包含:
Elevator:仅负责电梯的属性管理(楼层、状态、方向)与基础行为(开门、关门、移动一层);
PassengerRequest:封装乘客请求的属性(楼层、方向 / 类型);
RequestQueue:封装请求队列的增删改查与去重逻辑(处理重复请求);
ElevatorController:控制类,负责核心调度算法、输入处理与请求分发。
核心类图(基于 Mermaid 绘制):
Elevator

Metrics Details For File 'Main.java'
Parameter Value
========= =====
Project Directory D:\eclipse-workplace\experiment2\src\experiment2
Project Name 1234
Checkpoint Name Baseline2
File Name Main.java
Lines 582
Statements 173
Percent Branch Statements 13.3
Method Call Statements 81
Percent Lines with Comments 50.2
Classes and Interfaces 3
Methods per Class 12.00
Average Statements per Method 4.28
Line Number of Most Complex Method 45
Name of Most Complex Method PassengerCall.equals()
Maximum Complexity 4
Line Number of Deepest Block 148
Maximum Block Depth 4
Average Block Depth 1.40
Average Complexity 1.24
Most Complex Methods in 4 Class(es): Complexity, Statements, Max Depth, Calls
ElevatorCar.ElevatorCar() 1, 5, 2, 0
ElevatorCar.getHeading() 1, 1, 2, 0
ElevatorCar.getPosition() 1, 1, 2, 0
ElevatorCar.getStatus() 1, 1, 2, 0
ElevatorCar.isValidFloor() 2, 1, 2, 0
ElevatorCar.setHeading() 1, 1, 2, 0
ElevatorCar.setPosition() 1, 1, 2, 0
ElevatorCar.setStatus() 1, 1, 2, 0
handleDownward().target.ifPresent() 1, 3, 2, 3
handleUpward().target.ifPresent() 1, 3, 2, 3
PassengerCall.equals() 4, 6, 2, 1
PassengerCall.getDirection() 1, 1, 2, 0
PassengerCall.getFloor() 1, 1, 2, 0
PassengerCall.hashCode() 1, 1, 2, 1
PassengerCall.isInternal() 1, 1, 2, 1
PassengerCall.PassengerCall() 1, 2, 2, 1
PassengerCall.PassengerCall() 1, 2, 2, 1
Block Depth Statements
0 33
1 64
2 55
3 15
4 6
5 0
6 0
7 0
8 0
9+ 0

核心改进与心得
职责拆分:电梯类仅负责自身状态与基础行为,队列类负责请求的存储与去重,控制类负责调度与输入处理,完全遵循单一职责原则。例如,重复请求的过滤逻辑被封装在RequestQueue的isDuplicate方法中,无需在电梯类中编写冗余代码。
输入处理优化:新增无效请求过滤(楼层越界、重复请求),通过PassengerRequest的合法性校验与队列的去重方法实现。
调度算法解耦:调度逻辑被封装在控制类的schedule方法中,与电梯的基础行为(移动、开关门)分离,便于后续算法优化。
心得:类的拆分并非越细越好,而是要以 “职责” 为边界。本次设计中,PassengerRequest仅封装请求属性,RequestQueue仅管理队列操作,这种 “高内聚、低耦合” 的设计让代码的可维护性大幅提升 —— 例如,修改请求去重规则时,只需改动RequestQueue的isDuplicate方法,无需影响其他类。
题目三:引入乘客类的需求迭代设计
设计思路
题目三的核心变化是取消乘客请求类,引入乘客类(Passenger),并调整外部请求格式为<请求源楼层,请求目的楼层>,处理外部请求后需将目的楼层加入内部队列。类结构需再次适配,核心类包括:
Elevator:保持基础职责不变,新增内部请求队列的入队方法;
Passenger:封装乘客的属性(源楼层、目的楼层、请求类型:内部 / 外部);
RequestQueue:调整队列存储类型为Passenger,新增外部请求处理后向内部队列添加目的楼层的逻辑;
ElevatorController:适配新的外部请求格式,调整调度算法中外部请求的处理流程。
核心类图(基于 Mermaid 绘制):
Elevator

Metrics Details For File 'Main.java'
Parameter Value
========= =====
Project Directory D:\eclipse-workplace\experiment3\src\experiment3
Project Name 12345
Checkpoint Name Baseline3
File Name Main.java
Lines 497
Statements 228
Percent Branch Statements 17.5
Method Call Statements 78
Percent Lines with Comments 10.7
Classes and Interfaces 1
Methods per Class 48.00
Average Statements per Method 4.56
Line Number of Most Complex Method 181
Name of Most Complex Method Controller.processRequests()
Maximum Complexity 1
Line Number of Deepest Block 247
Maximum Block Depth 4
Average Block Depth 1.15
Average Complexity 1.00
Most Complex Methods in 1 Class(es): Complexity, Statements, Max Depth, Calls
Controller.Controller() 1, 2, 2, 0
Controller.Controller() 1, 2, 2, 0
Controller.getElevator() 1, 1, 2, 0
Controller.getQueue() 1, 1, 2, 0
Controller.processRequests() 1, 1, 2, 2
Controller.setElevator() 1, 1, 2, 0
Controller.setQueue() 1, 1, 2, 0
Block Depth Statements
0 62
1 97
2 47
3 16
4 6
5 0
6 0
7 0
8 0
9+ 0

核心变化与心得
乘客类的引入:乘客类替代了原有的请求类,更贴合业务场景 —— 请求不再是孤立的 “楼层 + 方向”,而是乘客的 “源楼层→目的楼层” 的完整行程。例如,外部请求的本质是 “乘客在源楼层呼叫电梯,前往目的楼层”,处理该请求时,电梯到达源楼层开门后,需将目的楼层加入内部队列。
调度逻辑适配:控制类新增processOuterRequest方法,专门处理外部乘客的请求:电梯到达源楼层→开门→将目的楼层加入内部队列→关门→继续移动。
队列结构调整:外部队列存储Passenger对象,内部队列存储目的楼层的整数,队列类的方法需适配新的存储类型。
心得:需求迭代时,类设计的稳定性至关重要。本次迭代中,电梯类的核心职责(状态管理、基础行为)未发生变化,仅新增了内部队列的入队方法,这正是开闭原则的体现 —— 对扩展开放,对修改关闭。而乘客类的引入让代码的业务语义更清晰,避免了原请求类的 “属性碎片化” 问题。
采坑心得
三次提交过程中遇到的问题多集中在类设计的耦合、调度算法的逻辑漏洞、输入处理的边界条件三个方面,以下结合具体案例与数据说明:
问题 1:单一类设计的职责臃肿(题目一)
题目要求设计一个电梯类,但我的代码中没有独立的Elevator类,而是将电梯的状态(当前楼层、方向)、调度逻辑、运行逻辑全部耦合在ElevatorController中。同时,电梯的运行状态(停止、移动中、开门、关门)完全缺失,仅通过打印Open/Close Door体现开关门,没有状态变量记录,不符合题目中 “电梯运行过程中的状态包括停止、移动中、开门、关门等” 的要求。题目要求 “电梯外部请求队列需要区分上行和下行”,但我将所有外部请求混存于一个outsideQueue中,仅通过peek()判断是否包含UP/DOWN来处理,导致同向优先的调度逻辑无法正确实现(无法批量处理所有同向的外部请求)。
问题 2:重复请求的过滤逻辑错误(题目二)
题目二明确要求必须包含电梯类、乘客请求类、队列类及控制类,但代码的类结构存在以下关键问题:无独立的乘客请求类:外部请求仅通过Elevator的私有静态内部类ExternalRequest实现,内部请求甚至未做封装(直接用Integer存储),未将 “乘客请求” 作为独立的公共类设计,不符合题目要求。无独立的队列类:请求队列直接使用Java.util.Queue的实现类(LinkedList),未封装队列的增删改查、去重、判空等逻辑为独立的队列类,电梯类直接操作队列,职责耦合。无独立的控制类:电梯的状态管理、请求处理、调度算法、运行逻辑全部耦合在Elevator类中,run方法承担了调度、移动、停靠、打印等所有核心职责,导致电梯类臃肿,违背 SRP。输入处理与请求过滤耦合在Main类:Main类同时承担输入读取、请求过滤、请求解析、电梯初始化等职责,虽未违反题目要求,但可进一步拆分为 “输入处理类” 和 “控制类” 提升内聚性。
问题 3:外部请求的目的楼层入队时机错误(题目三)
调度算法违背 “同向优先、顺路处理” 的核心规则,题目要求 “电梯向某个方向移动时,优先处理同方向的请求,每次移动一个楼层,检查是否有需要停靠的请求”,但代码的调度逻辑存在两个关键错误:
方向确定逻辑为 “找最近请求”,而非 “同向优先”:determineDirection()方法在电梯空闲时,通过getClosestInternalRequest()和getClosestExternalRequest()找最近的请求确定方向,而非优先处理同方向的顺路请求。例如,电梯在 3 楼,存在 4 楼的上行外部请求和 2 楼的下行内部请求,代码会优先处理更近的 2 楼请求,违背 “同向优先” 规则。
仅检查 “是否有同方向请求”,而非 “扫描顺路的所有请求”:hasRequestsInCurrentDirection()方法仅判断当前方向是否存在请求,未扫描电梯移动路径上的所有顺路请求。例如,电梯在 1 楼向上,存在 3 楼和 5 楼的外部请求,代码会移动到 3 楼处理后,再移动到 5 楼,但如果请求是 5 楼和 3 楼,代码会先移动到 5 楼,再折返处理 3 楼,违背 “顺路处理” 规则。
改进建议
三次迭代后的电梯调度程序虽实现了核心功能,但在可扩展性、算法优化、代码健壮性方面仍有较大改进空间,具体建议如下:
- 设计模式的引入
状态模式:电梯的 “停止、移动、开门、关门” 状态切换逻辑目前通过if-else实现,圈复杂度较高。引入状态模式,为每个状态创建对应的类(StopState、MovingState、OpenState),将状态切换的逻辑封装在状态类中,降低电梯类的复杂度。
工厂模式:乘客对象的创建目前直接在控制类中通过构造方法实现,若后续新增 “VIP 乘客”“无障碍乘客” 等类型,需修改控制类代码。引入简单工厂模式,创建PassengerFactory类负责乘客对象的实例化,符合开闭原则。 - 调度算法的优化
候梯时间优化:当前算法仅实现 “同向优先”,未考虑乘客的候梯时间。可新增 “请求优先级” 机制,对长时间未处理的请求提升优先级,减少乘客等待时间。
顺路请求合并:电梯移动时,可提前扫描路径上的所有请求(内部 + 外部),一次性规划移动路径,避免反复启停。
总结
知识点收获
本次三次题目集的迭代设计,让我对面向对象的设计原则有了从 “理论” 到 “实践” 的深刻理解:单一职责原则并非简单的类拆分,而是以 “职责” 为边界的模块化设计;开闭原则要求代码对扩展开放、对修改关闭,这需要在初期设计时预留足够的扩展接口。同时,我也掌握了电梯调度的核心算法(同向优先)、队列的增删改查与去重、输入处理的边界条件过滤等实战技能,提升了代码的调试与问题定位能力。
待深入学习的方向
多电梯调度算法:单部电梯的调度逻辑较为简单,多部电梯的负载均衡、请求分配是更复杂的问题,需学习相关的调度算法。
性能优化:当请求量较大时,队列的遍历与去重会产生性能瓶颈,需学习数据结构的优化。
课程改进建议
增加设计模式的实战案例:课堂上可结合电梯、图书馆管理系统等场景,讲解设计模式的应用,避免单纯的理论讲解。
引入代码评审环节:组织学生互评代码,从 “类设计、代码规范、算法逻辑” 等维度打分,提升代码的可读性与设计水平。
分阶段发布需求:类似本次的迭代设计,分阶段发布需求(基础功能→设计优化→功能扩展),让学生体验真实的项目开发流程。
提供测试用例集:在题目发布时,提供核心测试用例(如无效请求、重复请求),帮助学生提前发现问题,减少提交次数。
本次电梯调度程序的迭代设计,是一次宝贵的 “项目实战” 体验。它让我认识到,优秀的代码不仅能实现功能,更要具备可读性、可维护性与可扩展性。在后续的编程学习中,我会始终以设计原则为指导,写出更优雅、更健壮的代码。

浙公网安备 33010602011771号