23207225-华辉-第一次blog作业

一. 前言
在完成三次大作业的题集后,我兴高采烈地写下写下这片博客,思考人生的意义,也想和大家分享我在这三次大作业中碰见的问题和个人所得。代码为什么错了?错在哪?该如何才能通过题目的测试点?相信很多同学和我一样,在作业中有着类似的困扰。我会把完成作业时遇到的困惑都摆出来,深入思考背后的原因,尝试寻找解决办法。希望在这个过程中,我们能一起解开作业带来的谜团,找到更适合自己的学习方式。
1.关于题目
这三次大作业都是由几个小题和一个大题组成,前几个小题一般比较简单,用来给同学们练练手,真正需要同学们深入思考的是每次大作业的最后一道电梯调度的大题。并且题目都会提供相应的类图,来帮助我们完成代码。总的来说三次大作业的题集都是在帮助我们熟悉java的基础语法,巩固和加深语法的使用规范。
二.电梯调度
(一)第一次电梯调度
1.1题目要求
设计一个电梯类,具体包含电梯的最大楼层数、最小楼层数(默认为1层)当前楼层、运行方向、运行状态,以及电梯内部乘客的请求队列和电梯外部楼层乘客的请求队列,其中,电梯外部请求队列需要区分上行和下行。
电梯运行规则如下:电梯默认停留在1层,状态为静止,当有乘客对电梯发起请求时(各楼层电梯外部乘客按下上行或者下行按钮或者电梯内部乘客按下想要到达的楼层数字按钮),电梯开始移动,当电梯向某个方向移动时,优先处理同方向的请求,当同方向的请求均被处理完毕然后再处理相反方向的请求。电梯运行过程中的状态包括停止、移动中、开门、关门等状态。当电梯停止时,如果有新的请求,就根据请求的方向或位置决定移动方向。电梯在运行到某一楼层时,检查当前是否有请求(访问电梯内请求队列和电梯外请求队列),然后据此决定移动方向。每次移动一个楼层,检查是否有需要停靠的请求,如果有,则开门,处理该楼层的请求,然后关门继续移动。
使用键盘模拟输入乘客的请求,此时要注意处理无效请求情况,例如无效楼层请求,比如超过大楼的最高或最低楼层。还需要考虑电梯的空闲状态,当没有请求时,电梯停留在当前楼层。
请编写一个Java程序,设计一个电梯类,包含状态管理、请求队列管理以及调度算法,并使用一些测试用例,模拟不同的请求顺序,观察电梯的行为是否符合预期,比如是否优先处理同方向的请求,是否在移动过程中处理顺路的请求等。为了降低编程难度,不考虑同时有多个乘客请求同时发生的情况,即采用串行处理乘客的请求方式(电梯只按照规则响应请求队列中当前的乘客请求,响应结束后再响应下一个请求),具体运行规则详见输入输出样例。

输入格式:
第一行输入最小电梯楼层数。
第二行输入最大电梯楼层数。
从第三行开始每行输入代表一个乘客请求。

电梯内乘客请求格式:<楼层数>
电梯外乘客请求格式:<乘客所在楼层数,乘梯方向>,其中,乘梯方向用UP代表上行,用DOWN代表下行(UP、DOWN必须大写)。
当输入“end”时代表输入结束(end不区分大小写)。
输出格式:
模拟电梯的运行过程,输出方式如下:

运行到某一楼层(不需要停留开门),输出一行文本:
Current Floor: 楼层数 Direction: 方向
运行到某一楼层(需要停留开门)输出两行文本:
Open Door # Floor 楼层数
Close Door

题目给的输入有

1
20
< 3,UP>
<5>
<6,DOWN>
<7>
<3>
end
对应答案为
Current Floor: 1 Direction: UP
Current Floor: 2 Direction: UP
Current Floor: 3 Direction: UP
Open Door # Floor 3
Close Door
Current Floor: 4 Direction: UP
Current Floor: 5 Direction: UP
Open Door # Floor 5
Close Door
Current Floor: 6 Direction: UP
Current Floor: 7 Direction: UP
Open Door # Floor 7
Close Door
Current Floor: 6 Direction: DOWN
Open Door # Floor 6
Close Door
Current Floor: 5 Direction: DOWN
Current Floor: 4 Direction: DOWN
Current Floor: 3 Direction: DOWN
Open Door # Floor 3
Close Door

1.2类的设计
ElevatorState 和 Direction 枚举 (Enums):
职责:定义电梯系统中的离散状态和行为。
分析:使用枚举可以极大地提高代码的可读性和类型安全性。例如,direction 字段的类型是 Direction,而不是一个模糊的 int 或 String,这杜绝了无效值的出现,并使代码意图一目了然。这是非常好的实践。
ExternalRequest 类:
职责:封装一个外部请求(即乘客在楼层按钮上按下的上行或下行请求)。
分析:它将请求的两个核心属性(目标楼层 floor 和方向 direction)捆绑在一起,形成一个不可分割的数据单元。这使得 RequestManager 对外部请求的管理变得更加清晰和高效。
RequestManager 类:
职责:作为请求的 “大脑”,负责管理(添加、删除、查询)所有的内部和外部请求队列,并根据当前电梯状态判断下一步动作。
分析:这是整个系统的核心。它封装了所有与请求处理相关的业务逻辑,如 needStop()(判断是否需要停靠)和 determineNextDirection()(虽然这个方法在 Main 中,但逻辑本应在这里)。通过集中管理请求,Main 类(电梯主体)可以专注于自身的状态(位置、方向)和物理行为(移动、开关门),而无需关心请求队列的复杂细节。
InputHandler 类:
职责:处理所有用户输入,包括解析楼层范围和请求指令,并将解析后的请求添加到 RequestManager 中。
分析:这又是一个职责分离的绝佳例子。它将繁琐的输入验证、格式解析工作从核心的电梯逻辑中剥离出来。Main 类不需要知道用户是如何输入的,它只需要知道有哪些请求。这使得代码易于测试和维护。
Main 类:
职责:代表电梯本身,维护其核心状态(当前楼层 currentFloor、运行方向 direction、工作状态 state),并协调各个组件完成电梯的整体运行流程。
分析:它扮演了 “控制器” 或 “协调者” 的角色。它拥有一个 RequestManager 的实例,通过调用其方法来获取决策依据(如是否需要停),然后执行相应的动作(如开门、移动)。
1.3类图

Please use '!option handwritten true' to enable handwrittenElevatorStateWORKSTOPIDLEDirectionUP(1)DOWN(-1)STOP(0)-value: int+Direction(int value)+getValue(): intExternalRequest-floor: int-direction: Direction+ExternalRequest(int floor, Direction direction)+getFloor(): int+getDirection(): DirectionRequestManager-internalRequests: List<Integer>-externalRequests: List<ExternalRequest>-minFloor: int-maxFloor: int+RequestManager(int minFloor, int maxFloor)+addinternalrequest(int floor): void+addexternalrequest(int floor, Direction dir): void+removerequestatfloor(int currentfloor, Direction currentDir): void+hasrequest(): boolean+needstop(int currentfloor, Direction currentDir): boolean+getFirstInternal(): int+getFirstExternalFloor(): int+getFirstExternalDir(): Direction-isvalidfloor(int floor): booleanInputHandler-scanner: Scanner+InputHandler(Scanner scanner)+readminfloor(): int+readmaxfloor(int minFloor): int+readrequest(): List<String>+parseandaddrequest(List<String> requestStrs, RequestManager rm): voidMain-maxFloor: int-minFloor: int-currentfloor: int-direction: Direction-state: ElevatorState-requestManager: RequestManager+Main(int min, int max)+processallrequest(): void+runonestep(): void-processstop(): void-determininenextdirection(): void+getrequestmanager(): RequestManager+main(String[] args): voidScannerArrayListusesusesusesuses
1.4代码分析
image

1.5踩坑心得
第一次电梯调度大作业主要问题在于弄懂电梯调度逻辑,在此之前,最好画好类图,对本次大作业应该用哪些类做好准备,不然代码写到一半再进行类的修改容易出错。然后就是揣测题目中电梯的调度逻辑。

想要你的代码通过题目给的输入并不难,但你会发现通过这份测试后,并没有完成这道题目。这说明你代码中的逻辑与题目要求的逻辑并不相同。或者说我们的代码中有许多没有考虑到的地方。于是我仔细看了题目给的电梯运行过程详解,发现里面有提到

取同向且离得近的请求,
此时将IQ和OQ两个队列中的队头的5层请求全部出队

到这里我意思到自己的代码逻辑确实与要求不太相同,于是我在后面也询问了一些同学,他们也与我讲了他们对这次电梯调度的理解。

判断方向的函数逻辑,当前方向是UP,找请求,去比当前楼层大的方向为UP的外部请求或者比当前楼层大的内部请求,停靠后只删除队头对应的请求。当前方向是DOWN,找请求,去比当前楼层小的方向为DOWN的外部请求或者比当前楼层小的内部请求,停靠后只删除队头对应的请求。当上述两种情况都没有时,这时候不考虑方向直接过去。

理清思路后再修改代码就比较迅速,也说明了读题才是关键。

(二)第二次电梯调度
2.1题目要求
对之前电梯调度程序进行迭代性设计,目的为解决电梯类职责过多的问题,类设计要求遵循单一职责原则(SRP),要求必须包含但不限于设计电梯类、乘客请求类、队列类以及控制类,电梯运行规则与前阶段单类设计相同,但要处理如下情况:

乘客请求楼层数有误,具体为高于最高楼层数或低于最低楼层数,处理方法:程序自动忽略此类输入,继续执行
乘客请求不合理,具体为输入时出现连续的相同请求,例如<3><3><3>或者<5,DOWN><5,DOWN>,处理方法:程序自动忽略相同的多余输入,继续执行,例如<3><3><3>过滤为<3>
2.2类的设计
ElevatorState 和 Direction 枚举 (Enums):
职责:定义系统中的离散状态和行为。

OutsideRequest 类:
职责:封装一个外部请求(即乘客在楼层按钮上按下的上行或下行请求)。

RequestQueue 类:
职责:作为请求的 “仓库”,负责管理(添加、删除、查询)所有的内部和外部请求队列。

Elevator 类:
职责:代表电梯本身,维护其核心状态(当前楼层 currentFloor、运行方向 direction、工作状态 state),并提供改变状态的方法(moveUp, moveDown, openDoor 等)。

ElevatorController 类:
职责:作为整个系统的 “大脑” 或 “调度器”,负责协调整个系统的运行。它根据 RequestQueue 中的请求和 Elevator 的当前状态,来决定下一步行动。

InputHandler 类:
职责:处理所有用户输入,包括解析楼层范围和请求指令,并将解析后的请求添加到 RequestQueue 中。

Main 类:
职责:程序的入口点,负责组装和初始化所有核心组件,并启动整个流程。
2.3类图
Please use '!option handwritten true' to enable handwrittenElevatorStateWORKSTOPIDLEDirectionUP(1)DOWN(-1)STOP(0)-value: int+Direction(int value)+getValue(): intOutsideRequest-floor: int-direction: Direction+OutsideRequest(int floor, Direction direction)+getFloor(): int+getDirection(): DirectionRequestQueue-internalRequests: List<Integer>-externalRequests: List<OutsideRequest>-minFloor: int-maxFloor: int+RequestQueue(int minFloor, int maxFloor)+appendInternalCall(int floor): void+removeInternalRequest(int floor): void+getTopInternalCall(): int+appendExternalCall(int floor, Direction dir): void+removeExternalRequest(int floor, Direction dir): void+getTopExternalRequest(): OutsideRequest+hasPendingCalls(): boolean-isValidFloor(int floor): booleanElevator-maxFloor: int-minFloor: int-currentFloor: int-direction: Direction-state: ElevatorState+Elevator(int min, int max)+moveUp(): void+moveDown(): void+openDoor(): void+closeDoor(): void+setState(ElevatorState state): void+getCurrentFloor(): int+getDirection(): Direction+setDirection(Direction direction): void+getState(): ElevatorState+getMinFloor(): int+getMaxFloor(): intElevatorController-elevator: Elevator-requestQueue: RequestQueue+ElevatorController(Elevator elevator, RequestQueue requestQueue)+processAllRequests(): void-executeOneStep(): void-needStop(int currentFloor): boolean-handleHalt(int currentFloor): void-decideNextDirection(int currentFloor): voidInputHandler-scanner: Scanner+InputHandler(Scanner scanner)+readLowestFloor(): int+readHighestFloor(int minFloor): int+readCallList(): List<String>+parseAndLoadCalls(List<String> requestStrs, RequestQueue rq): voidMain+main(String[] args): voidScannerArrayListusesusesusesuses
2.4代码分析
image

2.5分析总结
与第一次电梯调度大作业相比,这次多了类的设计以及处理连续的相同请求的要求。其调度逻辑与第一次并无出入。

(三)第三次电梯调度
3.1题目要求
对之前电梯调度程序再次进行迭代性设计,加入乘客类(Passenger),取消乘客请求类,类设计要求遵循单一职责原则(SRP),要求必须包含但不限于设计电梯类、乘客类、队列类以及控制类。
电梯运行规则与前阶段相同,但有如下变动情况:

乘客请求输入变动情况:外部请求由之前的<请求楼层数,请求方向>修改为<请求源楼层,请求目的楼层>
对于外部请求,当电梯处理该请求之后(该请求出队),要将<请求源楼层,请求目的楼层>中的请求目的楼层加入到请求内部队列(加到队尾)
3.2类的设计
Passenger类:
职责:纯粹的数据载体,记录单个乘客的出行信息。

RequestQueue类:
职责:管理两个队列:等待被接载的乘客队列(externalQueue)和已在电梯内、等待被送达的目标楼层队列(internalQueue)。

ElevatorController类:
职责:作为 “大脑”,其决策逻辑现在需要围绕 “乘客” 来展开。

InputHandler类:
职责:解析用户输入,并将其转换为相应的请求。
3.3类图
Please use '!option handwritten true' to enable handwrittenElevatorStateWORKSTOPIDLEDirectionUP(1)DOWN(-1)STOP(0)-value: int+Direction(int value)+getValue(): intPassenger-sourceFloor: int-targetFloor: int+Passenger(int sourceFloor, int targetFloor)+getSourceFloor(): int+getTargetFloor(): intRequestQueue-externalQueue: List<Passenger>-internalQueue: List<Integer>-minFloor: int-maxFloor: int+RequestQueue(int minFloor, int maxFloor)+addExternalRequest(Passenger passenger): void+removeHeadExternalRequest(): Passenger+getHeadExternalPassenger(): Passenger+addInternalRequest(int targetFloor): void+removeHeadInternalRequest(): void+getHeadInternalFloor(): int+hasPendingCalls(): boolean-isValidFloor(int floor): booleanElevator-maxFloor: int-minFloor: int-currentFloor: int-direction: Direction-state: ElevatorState+Elevator(int min, int max)+moveUp(): void+moveDown(): void+openDoor(): void+closeDoor(): void+setState(ElevatorState state): void+getCurrentFloor(): int+getDirection(): Direction+setDirection(Direction direction): void+getState(): ElevatorState+getMinFloor(): int+getMaxFloor(): intElevatorController-elevator: Elevator-requestQueue: RequestQueue+ElevatorController(Elevator elevator, RequestQueue requestQueue)+processAllRequests(): void-executeOneStep(): void-decideInitialDirection(): void-needStop(int currentFloor): boolean-handleHalt(int currentFloor): void-decideNextDirection(int currentFloor): voidInputHandler-scanner: Scanner+InputHandler(Scanner scanner)+readLowestFloor(): int+readHighestFloor(int minFloor): int+readCallList(): List<String>+parseAndLoadCalls(List<String> requestStrs, RequestQueue rq): voidMain+main(String[] args): voidScannerArrayListusesusesusesuses
3.4代码分析
image

3.5分析总结
最后一次电梯调度的主要目标还是对类进行修改,通过Passenger类的引入,封装了乘客的起点楼层(sourceFloor)和目标楼层(targetFloor)。这使得外部请求不再是一个简单的<楼层, 方向>对,而是一个完整的、有始有终的乘客旅程。
请求处理流程的闭环:
一个外部请求(由Passenger对象代表)被加入队列。
电梯到达乘客所在楼层(sourceFloor)。
在handleHalt方法中,电梯 “接走” 乘客(移除外部队列的请求),并立即为该乘客在内部队列中添加一个前往其目标楼层(targetFloor)的请求。
电梯继续运行,最终将乘客送至目的地(处理内部队列的请求)。
这个流程完美地模拟了真实电梯的载客过程,使得整个系统的逻辑更加连贯和真实。
3.6踩坑心得
最后的电梯调度是我基于第二次大作业的基础上进行修改,最后并没有得到满分,我认为问题应该是出在最后修改的调度逻辑上.
三.总结
三次大作业围绕电梯调度问题逐步演进,在类的设计与职责划分上越来越清晰,功能逻辑也渐趋完善,体现了从简单到复杂、从耦合到解耦的迭代过程。在完成三次电梯调度大作业的过程中,我不仅巩固了 Java 基础语法,更在面向对象设计、问题拆解与算法逻辑层面获得了宝贵的实践经验。作为一名初学者,这段经历让我深刻体会到编程从 "实现功能" 到 "优化设计" 的进阶之路。

posted @ 2025-11-22 15:41  hhhh聪明勇敢有力气  阅读(9)  评论(0)    收藏  举报