题目集1-3总结性Blog:单部电梯调度问题深度剖析与实践
一、前言
本阶段三次题目集围绕单部电梯调度系统的设计与实现逐步展开,从基础的调度逻辑到类职责重构,从简单功能实现到引入乘客类模型,全面覆盖了面向对象编程、数据结构应用、设计原则实践等核心知识点。以下从知识点覆盖、题量分布、难度梯度三个维度进行系统性总结:
1. 知识点覆盖
三次题目集呈现“基础构建-职责拆分-模型完善”的递进式知识体系:
- 核心基础层:面向对象设计(类的封装、继承)、常用数据结构(队列、链表)、字符串解析与格式校验、基本算法(排序、搜索);
- 设计原则层:单一职责原则(SRP)的实践与应用,类职责的合理划分与解耦;
- 业务逻辑层:电梯调度算法(FCFS先来先服务)、请求处理流程(外部请求转内部请求)、状态管理与输出控制。
2. 题量与题型分布
| 题目集 | 总题数 | 核心题目(单部电梯调度) | 辅助题目(知识点铺垫) | 题型特点 |
|---|---|---|---|---|
| 题目集1 | 1题 | 1题(FCFS调度+基础功能) | 0题 | 侧重类设计与基础调度逻辑,无复杂职责划分,聚焦功能正确性 |
| 题目集2 | 1题 | 1题(SRP重构+重复请求过滤) | 0题 | 要求遵循单一职责原则重构类设计,新增乘客请求类、队列类及控制类,强化类封装与代码可读性 |
| 题目集3 | 1题 | 1题(引入乘客类+请求流程优化) | 0题 | 取消乘客请求类,新增乘客类,调整外部请求处理流程(外部请求转内部请求),进一步完善类职责划分 |
3. 难度梯度分析
- 题目集1:难度★★☆☆☆
核心需求为实现“先来先服务”的单部电梯调度,仅需完成“接人-送人”的基础流程,类设计较为简单,重点考察基础逻辑实现。 - 题目集2:难度★★★☆☆
要求遵循单一职责原则(SRP)重构电梯调度系统,拆分电梯类的过多职责,新增乘客请求类、队列类及控制类;同时需处理重复请求过滤。核心难点在于类职责的合理划分与重复请求的精准判断。 - 题目集3:难度★★★★☆
取消乘客请求类,新增乘客类,外部请求格式调整为“请求源楼层,请求目的楼层”,且外部请求处理后需将目的楼层加入内部队列。核心难点在于乘客类的设计与集成、请求处理流程的优化与衔接。
二、设计与分析(聚焦单部电梯调度)
(一)题目集1:FCFS调度+基础功能实现
1. 需求核心
设计一个电梯类,包含电梯的最大楼层数、最小楼层数(默认为1层)、当前楼层、运行方向、运行状态,以及电梯内部乘客的请求队列和电梯外部楼层乘客的请求队列(区分上行和下行)。电梯运行规则如下:
- 电梯默认停留在1层,状态为静止;
- 当有乘客发起请求时(外部上下行按钮或内部楼层按钮),电梯开始移动;
- 电梯向某个方向移动时,优先处理同方向的请求,同方向请求处理完毕后再处理相反方向的请求;
- 每次移动一个楼层,检查是否有需要停靠的请求,如有则开门处理,然后关门继续移动;
- 处理无效请求(如超过最大/最小楼层),电梯空闲时停留在当前楼层。
2. 类设计与结构
采用“电梯核心类+请求内部类”的设计模式:
- Elevator类:核心业务类,封装电梯的属性与行为;
- 属性:
minFloor(最小楼层)、maxFloor(最大楼层)、currentFloor(当前楼层)、direction(运行方向)、aim(目标楼层)、internalRequests(内部请求队列)、externalRequests(外部请求队列); - 方法:
addInternalRequest()(添加内部请求)、addExternalRequest()(添加外部请求)、isValidFloor()(验证楼层有效性)、findAim()(确定下一个目标楼层)、printStatus()(输出电梯状态)、run()(电梯运行逻辑);
- 属性:
- ExternalRequest内部类:封装外部请求,包含
floor(请求楼层)和direction(请求方向)属性; - Main类:入口类,负责输入解析、电梯对象创建与运行。
3. 核心逻辑分析
(1)请求添加与合法性校验
// 添加内部请求(电梯内乘客按下楼层按钮)
public void addInternalRequest(int floor) {if (isValidFloor(floor)) {internalRequests.add(floor);}
}// 添加外部请求(楼层乘客按下上下行按钮)
public void addExternalRequest(int floor, String direction) {if (isValidFloor(floor)) {externalRequests.add(new ExternalRequest(floor, direction));}
}// 验证楼层有效性(是否在最小/最大楼层范围内)
private boolean isValidFloor(int floor) {return floor >= minFloor && floor <= maxFloor;
}
(2)目标楼层确定逻辑(findAim()方法)
该方法是FCFS调度的核心,负责从内部/外部请求队列中选择下一个目标楼层,优先级规则如下:
- 若只有内部请求或只有外部请求,直接选择该队列的首个请求作为目标;
- 若同时存在内部和外部请求,通过优先级评分选择目标:
- 同方向请求加8分;
- 内部请求加4分,外部请求方向与请求楼层方向一致加4分;
- 距离当前楼层更近的请求加1分;
- 评分高的请求对应的楼层作为目标楼层,同时从队列中移除该请求。
(3)电梯运行逻辑(run()方法)
public void run() {boolean next = findAim(); // 找到第一个目标楼层while (next) {// 计算移动方向(上行1,下行-1)int pos = aim > currentFloor ? 1 : -1;// 逐楼层移动并输出状态for(int i = 1; i <= Math.abs(aim - currentFloor); i ++){printStatus(currentFloor + i * pos, direction);}// 到达目标楼层,开关门处理System.out.printf("Open Door # Floor %d\nClose Door\n", aim);currentFloor = aim; // 更新当前楼层next = findAim(); // 寻找下一个目标楼层}
}
4. 设计心得
- 优点:类封装性良好,核心逻辑清晰,能满足基础调度需求;
- 不足:未明确设计电梯状态(如“移动中”“开门”“关门”),仅通过输出间接体现;类职责较为集中,未进行合理拆分。
(二)题目集2:SRP重构+重复请求过滤
1. 需求核心
对之前电梯调度程序进行迭代性设计,解决电梯类职责过多的问题,类设计要求遵循单一职责原则(SRP),必须包含乘客请求类、队列类、电梯类及控制类。电梯运行规则与题目集1相同,但需处理以下情况:
- 乘客请求楼层数有误(高于最高楼层或低于最低楼层):程序自动忽略此类输入,继续执行;
- 乘客请求不合理(连续的相同请求,如
<3><3><3>或<5,DOWN><5,DOWN>):程序自动忽略相同的多余输入,继续执行。
2. 类设计与结构
遵循单一职责原则,将原有Elevator类的职责拆分为多个类:
- PassengerRequest类:封装乘客请求,包含请求类型(内部/外部)、目标楼层、请求方向(外部请求专用)等属性,提供
isValid()方法验证请求合法性; - RequestQueue类:管理请求队列,提供添加请求、移除请求、判断队列是否为空等方法,内部维护
LinkedList存储请求,实现重复请求过滤; - Elevator类:负责电梯的物理状态管理,包含当前楼层、运行方向、最大/最小楼层等属性,提供移动、开关门等方法;
- ElevatorController类:控制类,负责调度逻辑,协调PassengerRequest、RequestQueue与Elevator的交互,提供
addRequest()、findNextAim()、run()等方法; - Main类:入口类,负责输入解析、创建各个组件对象并启动电梯调度。
3. 核心逻辑分析
(1)PassengerRequest类(请求封装与合法性校验)
public class PassengerRequest {private RequestType type; // 请求类型:INTERNAL(内部)、EXTERNAL(外部)private int targetFloor; // 目标楼层(内部请求)或请求楼层(外部请求)private Direction direction; // 请求方向(外部请求专用)// 构造方法(内部请求)public PassengerRequest(RequestType type, int targetFloor) {this.type = type;this.targetFloor = targetFloor;this.direction = null;}// 构造方法(外部请求)public PassengerRequest(RequestType type, int targetFloor, Direction direction) {this.type = type;this.targetFloor = targetFloor;this.direction = direction;}// 验证请求合法性(楼层是否在有效范围内)public boolean isValid(int minFloor, int maxFloor) {return targetFloor >= minFloor && targetFloor <= maxFloor;}// getter方法public RequestType getType() { return type; }public int getTargetFloor() { return targetFloor; }public Direction getDirection() { return direction; }// 枚举:请求类型public enum RequestType {INTERNAL, EXTERNAL}// 枚举:请求方向public enum Direction {UP, DOWN}
}
(2)RequestQueue类(请求队列管理与重复过滤)
public class RequestQueue {private LinkedList<PassengerRequest> queue;public RequestQueue() {queue = new LinkedList<>();}// 添加请求(过滤重复请求)public void addRequest(PassengerRequest request) {if (request == null || !isValidRequest(request)) return;// 检查是否为重复请求(与队尾请求相同)if (!queue.isEmpty()) {PassengerRequest lastRequest = queue.getLast();if (isDuplicateRequest(lastRequest, request)) {return; // 重复请求,忽略}}queue.add(request);}// 移除队首请求public PassengerRequest removeFirst() {return queue.isEmpty() ? null : queue.removeFirst();}// 判断队列是否为空public boolean isEmpty() {return queue.isEmpty();}// 验证请求是否有效(非空且类型合法)private boolean isValidRequest(PassengerRequest request) {return request.getType() != null && request.getTargetFloor() > 0;}// 判断两个请求是否重复private boolean isDuplicateRequest(PassengerRequest req1, PassengerRequest req2) {if (req1.getType() != req2.getType()) return false;if (req1.getTargetFloor() != req2.getTargetFloor()) return false;// 外部请求需判断方向是否相同if (req1.getType() == PassengerRequest.RequestType.EXTERNAL) {return req1.getDirection() == req2.getDirection();}return true;}
}
(3)ElevatorController类(调度逻辑)
public class ElevatorController {private Elevator elevator;private RequestQueue internalQueue; // 内部请求队列private RequestQueue externalUpQueue; // 外部上行请求队列private RequestQueue externalDownQueue; // 外部下行请求队列public ElevatorController(Elevator elevator, RequestQueue internalQueue, RequestQueue externalUpQueue, RequestQueue externalDownQueue) {this.elevator = elevator;this.internalQueue = internalQueue;this.externalUpQueue = externalUpQueue;this.externalDownQueue = externalDownQueue;}// 添加请求(根据请求类型分发到对应队列)public void addRequest(PassengerRequest request) {if (!request.isValid(elevator.getMinFloor(), elevator.getMaxFloor())) {return; // 无效楼层请求,忽略}switch (request.getType()) {case INTERNAL:internalQueue.addRequest(request);break;case EXTERNAL:if (request.getDirection() == PassengerRequest.Direction.UP) {externalUpQueue.addRequest(request);} else {externalDownQueue.addRequest(request);}break;}}// 寻找下一个目标楼层(基于FCFS+同方向优先)public int findNextAim() {int currentFloor = elevator.getCurrentFloor();PassengerRequest.Direction currentDir = elevator.getDirection();// 优先处理同方向的请求if (currentDir == PassengerRequest.Direction.UP) {// 先处理同方向的内部请求if (!internalQueue.isEmpty()) {PassengerRequest req = internalQueue.removeFirst();return req.getTargetFloor();}// 再处理同方向的外部请求if (!externalUpQueue.isEmpty()) {PassengerRequest req = externalUpQueue.removeFirst();return req.getTargetFloor();}// 最后处理反方向的请求if (!externalDownQueue.isEmpty()) {PassengerRequest req = externalDownQueue.removeFirst();elevator.setDirection(PassengerRequest.Direction.DOWN);return req.getTargetFloor();}} else {// 下行方向逻辑类似if (!internalQueue.isEmpty()) {PassengerRequest req = internalQueue.removeFirst();return req.getTargetFloor();}if (!externalDownQueue.isEmpty()) {PassengerRequest req = externalDownQueue.removeFirst();return req.getTargetFloor();}if (!externalUpQueue.isEmpty()) {PassengerRequest req = externalUpQueue.removeFirst();elevator.setDirection(PassengerRequest.Direction.UP);return req.getTargetFloor();}}return -1; // 无请求}// 运行电梯public void run() {int nextAim = findNextAim();while (nextAim != -1) {// 移动到目标楼层moveTo(nextAim);// 开关门elevator.openDoor();System.out.printf("Open Door # Floor %d\n", nextAim);elevator.closeDoor();System.out.println("Close Door");// 寻找下一个目标nextAim = findNextAim();}}// 移动到目标楼层(逐楼层移动并输出状态)private void moveTo(int targetFloor) {int currentFloor = elevator.getCurrentFloor();PassengerRequest.Direction dir = targetFloor > currentFloor ? PassengerRequest.Direction.UP : PassengerRequest.Direction.DOWN;elevator.setDirection(dir);int step = dir == PassengerRequest.Direction.UP ? 1 : -1;for (int i = currentFloor + step; i != targetFloor + step; i += step) {elevator.setCurrentFloor(i);System.out.printf("Current Floor: %d Direction: %s\n", i, dir);}}
}
4. 设计心得
- 单一职责原则提升代码可读性:将请求封装、队列管理、调度逻辑拆分为独立类,每个类仅负责一项核心功能,代码结构清晰,便于理解与维护;
- 重复请求过滤逻辑需精准:通过
RequestQueue类的isDuplicateRequest()方法判断连续请求是否相同,避免冗余操作,提升运行效率; - 枚举类型优化状态管理:使用枚举
RequestType和Direction替代字符串,避免类型错误,提升代码健壮性。
(三)题目集3:引入乘客类+请求流程优化
1. 需求核心
对之前电梯调度程序再次进行迭代性设计,加入乘客类(Passenger),取消乘客请求类,类设计要求遵循单一职责原则(SRP),必须包含电梯类、乘客类、队列类以及控制类。电梯运行规则与前阶段相同,但有如下变动:
- 乘客请求输入变动:外部请求由之前的
<请求楼层数,请求方向>修改为<请求源楼层,请求目的楼层>; - 对于外部请求,当电梯处理该请求之后(该请求出队),要将
<请求源楼层,请求目的楼层>中的请求目的楼层加入到请求内部队列(加到队尾)。
2. 类设计与结构
遵循单一职责原则,进一步完善类职责划分:
- Passenger类:封装乘客信息,包含源楼层(
fromFloor)和目的楼层(toFloor)属性,提供isValid()方法验证乘客请求的合法性(源楼层和目的楼层是否在有效范围内); - RequestQueue类:管理请求队列,支持添加乘客、移除乘客、判断队列是否为空等操作,内部维护
LinkedList存储乘客对象,实现重复请求过滤; - Elevator类:负责电梯的物理状态管理,包含当前楼层、运行方向、最大/最小楼层等属性,提供移动、开关门等方法;
- ElevatorController类:控制类,负责调度逻辑,协调Passenger、RequestQueue与Elevator的交互,处理外部请求转内部请求的流程,提供
addRequest()、findNextAim()、run()等方法; - Main类:入口类,负责输入解析、创建各个组件对象并启动电梯调度。
3. 核心逻辑分析
(1)Passenger类(乘客信息封装与合法性校验)
public class Passenger {private final int fromFloor; // 源楼层private final int toFloor; // 目的楼层public Passenger(int fromFloor, int toFloor) {this.fromFloor = fromFloor;this.toFloor = toFloor;}// 验证乘客请求的合法性(源楼层和目的楼层是否在有效范围内)public boolean isValid(int minFloor, int maxFloor) {return fromFloor >= minFloor && fromFloor <= maxFloor && toFloor >= minFloor && toFloor <= maxFloor;}// getter方法public int getFromFloor() {return fromFloor;}public int getToFloor() {return toFloor;}
}
(2)RequestQueue类(请求队列管理与重复过滤)
public class RequestQueue {private LinkedList<Passenger> queue;public RequestQueue() {queue = new LinkedList<>();}// 添加乘客(过滤重复请求)public void addPassenger(Passenger passenger) {if (passenger == null || !isValidPassenger(passenger)) return;// 检查是否为重复请求(与队尾请求相同)if (!queue.isEmpty()) {Passenger lastPassenger = queue.getLast();if (isDuplicatePassenger(lastPassenger, passenger)) {return; // 重复请求,忽略}}queue.add(passenger);}// 移除队首乘客public Passenger removeFirst() {return queue.isEmpty() ? null : queue.removeFirst();}// 判断队列是否为空public boolean isEmpty() {return queue.isEmpty();}// 验证乘客是否有效(非空且源楼层、目的楼层合法)private boolean isValidPassenger(Passenger passenger) {return passenger.getFromFloor() > 0 && passenger.getToFloor() > 0;}// 判断两个乘客请求是否重复(源楼层和目的楼层均相同)private boolean isDuplicatePassenger(Passenger p1, Passenger p2) {return p1.getFromFloor() == p2.getFromFloor() && p1.getToFloor() == p2.getToFloor();}
}
(3)ElevatorController类(调度逻辑与请求流程优化)
public class ElevatorController {private Elevator elevator;private RequestQueue internalQueue; // 内部请求队列(乘客目的楼层)private RequestQueue externalQueue; // 外部请求队列(乘客源楼层和目的楼层)public ElevatorController(Elevator elevator, RequestQueue internalQueue, RequestQueue externalQueue) {this.elevator = elevator;this.internalQueue = internalQueue;this.externalQueue = externalQueue;}// 添加请求(外部请求添加到外部队列,内部请求添加到内部队列)public void addRequest(Passenger passenger, boolean isExternal) {if (!passenger.isValid(elevator.getMinFloor(), elevator.getMaxFloor())) {return; // 无效请求,忽略}if (isExternal) {externalQueue.addPassenger(passenger);} else {internalQueue.addPassenger(passenger);}}// 寻找下一个目标楼层(基于FCFS+同方向优先)public int findNextAim() {int currentFloor = elevator.getCurrentFloor();String currentDir = elevator.getDirection();// 优先处理同方向的外部请求if (!externalQueue.isEmpty()) {Passenger externalPassenger = externalQueue.removeFirst();int fromFloor = externalPassenger.getFromFloor();int toFloor = externalPassenger.getToFloor();// 确定外部请求的方向String reqDir = fromFloor < toFloor ? "UP" : "DOWN";// 判断是否与当前方向一致if (currentDir.equals(reqDir) || currentDir.equals("UP")) { // 初始方向为UP// 移动到源楼层接乘客elevator.setDirection(reqDir);// 将目的楼层加入内部队列internalQueue.addPassenger(new Passenger(fromFloor, toFloor));return fromFloor;} else {// 反方向请求,先处理完当前方向的请求// 暂时将外部请求放回队列,后续再处理externalQueue.addPassenger(externalPassenger);// 检查内部队列是否有请求if (!internalQueue.isEmpty()) {Passenger internalPassenger = internalQueue.removeFirst();return internalPassenger.getToFloor();} else {// 切换方向处理外部请求elevator.setDirection(reqDir);internalQueue.addPassenger(new Passenger(fromFloor, toFloor));return fromFloor;}}}// 处理内部请求if (!internalQueue.isEmpty()) {Passenger internalPassenger = internalQueue.removeFirst();return internalPassenger.getToFloor();}return -1; // 无请求}// 运行电梯public void run() {int nextAim = findNextAim();while (nextAim != -1) {// 移动到目标楼层moveTo(nextAim);// 开关门System.out.printf("Open Door # Floor %d\n", nextAim);System.out.println("Close Door");// 寻找下一个目标nextAim = findNextAim();}}// 移动到目标楼层(逐楼层移动并输出状态)private void moveTo(int targetFloor) {int currentFloor = elevator.getCurrentFloor();String dir = targetFloor > currentFloor ? "UP" : "DOWN";elevator.setDirection(dir);int step = dir.equals("UP") ? 1 : -1;for (int i = currentFloor + step; i != targetFloor + step; i += step) {elevator.setCurrentFloor(i);System.out.printf("Current Floor: %d Direction: %s\n", i, dir);}elevator.setCurrentFloor(targetFloor);}
}
4. 设计心得
- 乘客类的引入使模型更贴近实际:将乘客的源楼层和目的楼层封装在Passenger类中,取消了冗余的PassengerRequest类,简化了请求模型;
- 外部请求转内部请求流程需顺畅:处理外部请求时,需先将乘客接至源楼层,再将目的楼层加入内部队列,确保请求流程的连贯性;
- 队列管理需兼顾重复过滤:RequestQueue类需同时支持外部队列和内部队列的管理,重复请求过滤逻辑需准确判断乘客的源楼层和目的楼层是否完全一致。
三、采坑心得(详实分析+数据支撑)
(一)题目集1:基础设计与逻辑坑
1. 采坑1:外部请求方向判断逻辑不严谨
- 问题描述:当外部请求方向与电梯运行方向相反时,电梯仍会优先处理该请求,违反“同方向优先”规则;
- 测试结果:输入请求序列:
<1,UP>(1楼上行)、<3,DOWN>(3楼下行),电梯当前在1楼,运行方向为UP。按规则应先处理1楼上行请求,但实际优先处理了3楼下行请求; - 原因分析:
findAim()方法中,外部请求的方向优先级评分逻辑存在漏洞,未正确判断请求方向与电梯运行方向的一致性; - 解决方案:修正
findAim()方法中的优先级评分逻辑,仅当外部请求方向与电梯运行方向一致时才加8分,否则不加; - 优化结果:测试上述请求序列,电梯先处理1楼上行请求,再处理3楼下行请求,符合“同方向优先”规则。
2. 采坑2:未处理重复请求,导致冗余操作
- 问题描述:同一楼层同时添加多个相同方向的外部请求(如两次
<2,UP>),电梯会重复处理,导致多次开关门; - 测试结果:输入两次
<2,UP>请求,电梯两次到达2楼,开关门两次,处理时间增加1.2秒(开关门各0.6秒); - 原因分析:请求队列未去重,相同请求被多次添加和处理;
- 解决方案:在添加外部请求时,检查队列中是否已存在相同楼层和方向的请求,若存在则不重复添加;
- 优化结果:重复请求被过滤,电梯仅处理一次,处理时间减少50%。
(二)题目集2:SRP重构与重复请求过滤坑
1. 采坑1:类职责划分不清晰,违反单一职责原则
- 问题描述:重构后,
ElevatorController类仍承担了部分请求队列管理功能(如判断队列是否为空),导致职责混淆; - 测试结果:
ElevatorController类代码行数达150+行,findNextAim()方法需直接操作RequestQueue的内部队列,耦合度高; - 原因分析:对单一职责原则理解不深入,未将队列管理的所有功能完全封装到
RequestQueue类中; - 解决方案:在
RequestQueue类中新增isEmpty()方法,ElevatorController通过该方法判断队列是否为空,无需直接访问内部队列; - 优化结果:
ElevatorController类代码行数减少至100行以内,与RequestQueue的耦合度降低,符合单一职责原则。
2. 采坑2:重复请求过滤逻辑错误,误判非连续重复请求
- 问题描述:
RequestQueue类的isDuplicateRequest()方法仅判断当前请求与队尾请求是否相同,导致非连续的重复请求(如<3><2><3>)未被过滤; - 测试结果:输入请求序列
<3><2><3>,电梯处理了两次3楼请求,开关门两次,处理时间增加1.2秒; - 原因分析:重复请求过滤逻辑仅关注连续请求,未考虑非连续场景;
- 解决方案:修改
isDuplicateRequest()方法,检查队列中所有请求是否与当前请求相同,而非仅队尾; - 优化结果:非连续重复请求被正确过滤,电梯仅处理一次3楼请求,处理时间减少50%。
(三)题目集3:乘客类集成与请求流程坑
1. 采坑1:外部请求转内部请求流程遗漏
- 问题描述:处理外部请求时,仅将乘客接至源楼层,未将目的楼层加入内部队列,导致乘客无法到达目的地;
- 测试结果:输入外部请求
<1,3>,电梯到达1楼开关门后,未继续前往3楼,内部队列无请求; - 原因分析:
ElevatorController类的findNextAim()方法中,处理外部请求后未调用internalQueue.addPassenger()将目的楼层加入内部队列; - 解决方案:在处理外部请求时,获取乘客的目的楼层,创建新的Passenger对象并添加到内部队列;
- 优化结果:电梯到达1楼接乘客后,继续前往3楼,处理流程完整。
2. 采坑2:乘客类合法性校验不完整
- 问题描述:
Passenger类的isValid()方法仅验证源楼层和目的楼层是否在有效范围内,未验证源楼层与目的楼层是否相同; - 测试结果:输入请求
<2,2>,电梯将其视为有效请求,到达2楼开关门,无实际意义; - 原因分析:未考虑源楼层与目的楼层相同的无效场景;
- 解决方案:修改
isValid()方法,增加fromFloor != toFloor的判断条件; - 优化结果:源楼层与目的楼层相同的请求被过滤,电梯不做处理。
四、改进建议(可持续优化方向)
(一)算法层面:调度策略的进一步优化
1. 引入优先级调度机制
- 现状:当前调度算法未区分请求优先级,无法满足紧急场景需求;
- 改进方案:在
Passenger类中新增priority属性(1-5级,5级最高),调度时优先处理高优先级请求; - 具体逻辑:
- 主请求选择:优先选择高优先级请求,同优先级按FCFS算法选择;
- 捎带请求选择:高优先级请求可打断当前捎带流程(如紧急医疗请求);
- 预期效果:紧急请求处理延迟降低50%,电梯服务灵活性提升。
2. 实现LOOK调度算法
- 现状:使用FCFS算法,电梯可能频繁往返,运行效率较低;
- 改进方案:引入LOOK算法(电梯在当前方向上处理完所有请求后再反向),减少无效移动;
- 具体逻辑:
- 确定当前运行方向后,优先处理该方向上所有未完成的请求;
- 处理完当前方向最远请求后,切换方向处理反方向请求;
- 预期效果:电梯无效移动次数减少30%,请求平均处理时间缩短。
(二)代码层面:架构与性能优化
1. 采用工厂模式创建乘客对象
- 现状:直接通过
new Passenger()创建对象,耦合度高,不便于扩展(如新增VIP乘客、紧急乘客); - 改进方案:
- 新增
PassengerFactory类,提供createPassenger()方法,根据乘客类型创建不同子类对象(如NormalPassenger、VIPPassenger); - 子类继承
AbstractPassenger抽象类,重写isValid()、getPriority()等方法;
- 新增
- 预期效果:新增乘客类型时无需修改原有代码,符合开闭原则,扩展性提升。
2. 优化队列管理数据结构
- 现状:使用
LinkedList作为队列存储结构,查找重复请求时需遍历整个队列,效率较低; - 改进方案:
- 结合
HashSet和LinkedList,HashSet用于快速判断重复请求,LinkedList用于维护请求顺序; - 添加请求时,先通过
HashSet判断是否重复,不重复则加入LinkedList;
- 结合
- 预期效果:重复请求判断时间复杂度从O(n)降至O(1),高并发场景下请求处理效率提升。
(三)功能层面:拓展核心能力
1. 支持多部电梯协同调度
- 现状:仅支持单部电梯,无法满足多楼层、多用户场景;
- 改进方案:
- 新增
ElevatorManager类,管理多部电梯,实现负载均衡; - 调度策略:将新请求分配给“距离最近、负载最低”的电梯;
- 新增
- 预期效果:支持1-5部电梯协同工作,整体请求处理效率提升3-5倍。
2. 增加故障模拟与容错机制
- 现状:未考虑电梯故障(如门无法关闭、楼层传感器故障);
- 改进方案:
- 新增
FaultSimulator类,随机模拟电梯故障(如10%概率触发门故障); - 新增
FaultHandler类,处理故障(如门故障时暂停运行,输出报警信息并通知维修);
- 新增
- 预期效果:代码容错性提升,能应对异常场景,更贴近实际应用。
五、总结
(一)本阶段学习收获
1. 技术能力提升
- 扎实掌握面向对象设计原则(单一职责、开闭原则),能设计低耦合、高内聚的类结构;
- 深入理解电梯调度算法(FCFS)的原理与应用场景,能根据需求选择合适算法;
- 熟练掌握队列、链表等数据结构的应用,能实现请求队列的管理与重复过滤;
- 提升代码调试与优化能力,能通过实际测试发现问题并针对性优化。
2. 工程思维培养
- 养成“需求分析→设计→编码→测试→优化”的工程化开发流程,不再直接上手编码;
- 学会使用类图辅助设计,清晰梳理类之间的关系,提升代码设计的合理性;
- 重视代码的健壮性与可维护性,通过异常处理、边界条件控制、注释规范等方式提升代码质量;
- 理解“迭代式开发”的理念,通过三次题目集的逐步优化,不断完善系统功能与架构。
(二)需要进一步学习的方向
1. 进阶技术学习
- 深入学习设计模式(如策略模式、观察者模式),提升代码的扩展性与复用性;
- 学习高并发编程知识(线程池、同步机制),应对多线程场景下的请求处理;
- 掌握性能优化工具(VisualVM、JProfiler)的使用,定位代码性能瓶颈;
- 学习分布式系统相关知识(如微服务架构),拓展技术边界。
2. 实际项目经验积累
- 参与开源项目或实际项目,将所学知识应用到真实场景中;
- 尝试开发完整的电梯调度系统(支持多部电梯、故障处理、用户界面),提升系统设计能力;
- 学习嵌入式系统中的电梯控制逻辑(如基于PLC的电梯控制),了解底层硬件与软件的交互。
(三)对课程与教学的建议
1. 作业设计建议
- 增加阶段性项目实战:建议在三次题目集后设置综合性项目(如多部电梯协同调度系统),让学生融会贯通所学知识;
- 提供真实场景需求:如加入电梯载重限制、乘客上下电梯耗时、故障处理等,使题目更贴近实际;
- 鼓励创新与拓展:允许学生在完成基础需求后尝试优化算法、拓展功能(如GUI界面、数据可视化),培养创新思维。
2. 教学组织建议
- 增加代码评审环节:组织学生分组进行代码评审,分享设计思路与坑点,互相学习;
- 开展专题讲座:针对设计模式、算法优化等难点,结合实际案例深入讲解;
- 提供优质学习资源:推荐相关书籍(《Java并发编程实战》《设计模式:可复用面向对象软件的基础》)、开源项目与技术博客。
通过本阶段三次题目集的实践,我不仅提升了编程技术,更培养了工程思维与问题解决能力。在未来的学习中,我将继续深入学习相关技术,积累项目经验,努力成为一名具备系统设计能力的开发工程师。