第一次blog作业
前言:
本学期在 Java 学习过程中,我们完成了三次电梯设计相关的题目集,它们在知识点覆盖、题量及难度方面呈现出循序渐进的特点。
在知识点上,深度融合面向对象编程基础。我们要将电梯、乘客请求等现实元素抽象为类,合理定义类的属性与方法,并注重类的封装性,像电梯的当前楼层、运行方向等属性及开门、关门等操作都封装于电梯类中。程序流程控制也极为关键,需利用循环结构持续接收用户输入,通过条件判断处理各类请求及电梯的不同状态。数据结构的应用不可或缺,以队列来有序管理乘客请求,保障请求处理的先后顺序。
题量与难度呈现梯度变化。第一次题目集聚焦于基本输入输出操作和简单电梯运行逻辑的熟悉,题量较少,难度较低,是为搭建程序基本框架的引导。第二次题目集在请求多样性和电梯调度逻辑的复杂度上做了加法,题量增多,难度提升,要求我们更深入剖析电梯运行状态和请求处理机制。第三次题目集进一步拓展功能,引入更复杂场景与优化需求,题量较大且难度颇高,考验我们综合运用知识进行全面设计与优化的能力。
分析与设计:
第一次作业:
题目:
设计一个电梯类,具体包含电梯的最大楼层数、最小楼层数(默认为1层)当前楼层、运行方向、运行状态,以及电梯内部乘客的请求队列和电梯外部楼层乘客的请求队列,其中,电梯外部请求队列需要区分上行和下行。
电梯运行规则如下:电梯默认停留在1层,状态为静止,当有乘客对电梯发起请求时(各楼层电梯外部乘客按下上行或者下行按钮或者电梯内部乘客按下想要到达的楼层数字按钮),电梯开始移动,当电梯向某个方向移动时,优先处理同方向的请求,当同方向的请求均被处理完毕然后再处理相反方向的请求。电梯运行过程中的状态包括停止、移动中、开门、关门等状态。当电梯停止时,如果有新的请求,就根据请求的方向或位置决定移动方向。电梯在运行到某一楼层时,检查当前是否有请求(访问电梯内请求队列和电梯外请求队列),然后据此决定移动方向。每次移动一个楼层,检查是否有需要停靠的请求,如果有,则开门,处理该楼层的请求,然后关门继续移动。
使用键盘模拟输入乘客的请求,此时要注意处理无效请求情况,例如无效楼层请求,比如超过大楼的最高或最低楼层。还需要考虑电梯的空闲状态,当没有请求时,电梯停留在当前楼层。
请编写一个Java程序,设计一个电梯类,包含状态管理、请求队列管理以及调度算法,并使用一些测试用例,模拟不同的请求顺序,观察电梯的行为是否符合预期,比如是否优先处理同方向的请求,是否在移动过程中处理顺路的请求等。为了降低编程难度,不考虑同时有多个乘客请求同时发生的情况,即采用串行处理乘客的请求方式(电梯只按照规则响应请求队列中当前的乘客请求,响应结束后再响应下一个请求),具体运行规则详见输入输出样例。
输入格式:
第一行输入最小电梯楼层数。
第二行输入最大电梯楼层数。
从第三行开始每行输入代表一个乘客请求。
电梯内乘客请求格式:<楼层数>
电梯外乘客请求格式:<乘客所在楼层数,乘梯方向>,其中,乘梯方向用UP代表上行,用DOWN代表下行(UP、DOWN必须大写)。
当输入“end”时代表输入结束(end不区分大小写)。
输出格式:
模拟电梯的运行过程,输出方式如下:
运行到某一楼层(不需要停留开门),输出一行文本:
Current Floor: 楼层数 Direction: 方向
运行到某一楼层(需要停留开门)输出两行文本:
Open Door # Floor 楼层数
Close Door
分析:
类与属性设计:Elevator类通过minFloor、maxFloor确定楼层范围,currentFloor记录实时位置,currentDirection和currentStatus分别表示运行方向与状态。内部请求用Queue存储,外部请求则借助Map,以楼层为键,方向集合为值,方便管理不同楼层的多种方向请求 。
请求处理方法:addInternalRequest和addExternalRequest方法用于添加请求,会校验楼层有效性,避免无效请求干扰。processRequests方法作为核心,通过循环不断处理请求,直至队列清空。
调度逻辑方法:decideNextFloor方法是调度核心,根据电梯当前方向,调用findNextFloorInUpDirection或findNextFloorInDownDirection方法,优先处理同向请求;若同向无请求,则调整方向处理反向请求,确保符合运行规则。
运行与状态管理:moveElevator方法控制电梯移动并输出运行信息,processCurrentFloorRequests方法判断当前楼层是否有请求,有则执行开门、处理、关门操作,改变电梯状态。
主类逻辑:Main类负责读取用户输入,解析请求格式,创建Elevator实例并添加请求,最后调用processRequests驱动电梯模拟运行,直至请求处理完毕 。
心得:
在完成电梯模拟程序的过程中,我经历了从困惑到逐渐清晰的过程。最初面对复杂的运行规则和请求处理逻辑,常常感到无从下手,尤其是请求队列的管理和电梯方向判断的优先级问题,让我屡屡陷入困境。
在尝试编写代码时,我深刻体会到数据结构选择的重要性。我逐步理解了如何优先处理同向请求,以及在无同向请求时切换方向的机制。
处理无效请求和请求格式校验也让我意识到严谨性的重要。一个小的输入错误就可能导致程序异常,因此在addInternalRequest和addExternalRequest中对楼层有效性的判断,以及在主类中对输入格式的正则匹配,都是不可或缺的环节。
这次实践让我明白,复杂问题需要拆解成一个个小模块逐步解决。每一次调试和修改,都是对逻辑思维的锻炼,也让我对 Java 编程的理解更加深入,收获颇丰。
第二次作业:
对之前电梯调度程序进行迭代性设计,目的为解决电梯类职责过多的问题,类设计要求遵循单一职责原则(SRP),要求必须包含但不限于设计电梯类、乘客请求类、队列类以及控制类,具体设计可参考如下类图。
电梯迭代1类图.png
电梯运行规则与前阶段单类设计相同,但要处理如下情况:
乘客请求楼层数有误,具体为高于最高楼层数或低于最低楼层数,处理方法:程序自动忽略此类输入,继续执行
乘客请求不合理,具体为输入时出现连续的相同请求,例如<3><3><3>或者<5,DOWN><5,DOWN>,处理方法:程序自动忽略相同的多余输入,继续执行,例如<3><3><3>过滤为<3>
注意:本次作业类设计必须符合如上要求(包含但不限于乘客请求类、电梯类、请求队列类及控制类,其中控制类专门负责电梯调度过程),凡是不符合类设计要求此题不得分,另外,PTA得分代码界定为第一次提交的最高分代码(因此千万不要把第一次电梯程序提交到本次题目中测试)。
输入格式:
第一行输入最小电梯楼层数。
第二行输入最大电梯楼层数。
从第三行开始每行输入代表一个乘客请求。
电梯内乘客请求格式:<楼层数>
电梯外乘客请求格式:<乘客所在楼层数,乘梯方向>,其中,乘梯方向用UP代表上行,用DOWN代表下行(UP、DOWN必须大写)。
当输入“end”时代表输入结束(end不区分大小写)。
输出格式:
模拟电梯的运行过程,输出方式如下:
运行到某一楼层(不需要停留开门),输出一行文本:
Current Floor: 楼层数 Direction: 方向
运行到某一楼层(需要停留开门)输出两行文本:
Open Door # Floor 楼层数
Close Door
类图如下:

分析:

枚举类:定义了Direction(方向)和State(状态)枚举类,用于表示电梯的运行方向和状态。
外部请求类(ExternalRequest):表示电梯外的乘客请求,包含请求楼层和请求方向。
电梯类(Elevator):包含电梯当前楼层、运行方向、状态、最大楼层和最小楼层等属性,以及相关的访问和修改方法,还提供了判断楼层是否有效的方法。
请求队列类(RequestQueue):管理内部请求(电梯内乘客请求)和外部请求(电梯外乘客请求),提供添加请求和获取请求列表的方法。
控制类(Controller):负责电梯的调度逻辑,包括处理请求、控制电梯移动、判断是否停靠、开关门等操作。
主类(Main):读取输入,创建电梯、请求队列和控制器对象,将输入的请求加入队列,最后调用控制器的processRequests方法来模拟电梯运行。
这段 Java 代码是为实现电梯调度功能。先通过枚举定义电梯方向和状态,方便表示不同情况。然后分别构建了表示外部请求、电梯本身、请求队列以及控制逻辑的类。每个类都有自己明确的任务,比如电梯类管电梯状态,队列类管请求存储。控制类则处理调度核心逻辑。主函数负责接收输入并启动程序。整体结构清晰,按要求做到了职责分离。
第三次题目:
对之前电梯调度程序再次进行迭代性设计,加入乘客类(Passenger),取消乘客请求类,类设计要求遵循单一职责原则(SRP),要求必须包含但不限于设计电梯类、乘客类、队列类以及控制类,具体设计可参考如下类图。
类图.png
电梯运行规则与前阶段相同,但有如下变动情况:
乘客请求输入变动情况:外部请求由之前的<请求楼层数,请求方向>修改为<请求源楼层,请求目的楼层>
对于外部请求,当电梯处理该请求之后(该请求出队),要将<请求源楼层,请求目的楼层>中的请求目的楼层加入到请求内部队列(加到队尾)
注意:本次作业类设计必须符合如上要求(包含但不限于设计电梯类、乘客类、队列类以及控制类),凡是不符合类设计要求此题不得分,另外,PTA得分代码界定为第一次提交的最高分代码(因此千万不要把第一次及第二次电梯程序提交到本次题目中测试)。
输入格式:
第一行输入最小电梯楼层数。
第二行输入最大电梯楼层数。
从第三行开始每行输入代表一个乘客请求。
电梯内乘客请求格式:<楼层数>
电梯外乘客请求格式:<请求源楼层,请求目的楼层>,其中,请求源楼层表示乘客发起请求所在的楼层,请求目的楼层表示乘客想要到达的楼层。
当输入“end”时代表输入结束(end不区分大小写)。
类图如下:

这次代码我并未通过测试点,以下是我的分析和心得:
在进行本次电梯调度程序的迭代设计时,我首先明确了任务要求,即加入乘客类并取消乘客请求类,同时要遵循单一职责原则。基于此,我回顾了之前的设计,思考如何将乘客相关的信息和行为合理地封装到新的乘客类中。
对于请求格式的变化,从 <请求楼层数,请求方向> 变为 < 请求源楼层,请求目的楼层 >,这使得请求信息更加详细和具体。我意识到在处理请求时,需要更加细致地考虑乘客的起始和目标楼层,以确保电梯能够准确地响应乘客的需求。
在请求处理逻辑方面,要求电梯处理外部请求后将请求目的楼层加入内部队列,这增加了队列管理的复杂性。我思考如何在现有的队列类基础上进行扩展,以实现这一功能,同时保证代码的可读性和可维护性。
失败原因:在实现过程中,可能存在以下导致败北的原因。首先,类设计的调整可能没有充分考虑到各个类之间的交互和协作。虽然新增了乘客类,但可能在职责划分上不够清晰,导致类之间的耦合度增加,影响了代码的可扩展性和可维护性。
其次,请求格式的变化带来了新的挑战。在处理新的请求格式时,可能没有充分考虑到各种边界情况,导致程序在某些输入下出现错误。例如,可能没有对请求源楼层和请求目的楼层的有效性进行充分的验证,或者在将请求目的楼层加入内部队列时出现逻辑错误。
最后,请求处理逻辑的复杂性增加可能导致代码的实现难度增大。在处理外部请求和内部队列时,可能没有设计出合理的算法,导致程序的性能下降或者出现死循环等问题。此外,代码的调试和测试也可能不够充分,没有发现一些隐藏的错误。
感悟:这次电梯调度程序迭代失败让我深刻意识到,看似简单的需求变更背后,实则隐藏着诸多挑战。在类设计时,对单一职责原则的贯彻不够彻底,新增乘客类却未完全厘清其与其他类的边界,导致职责混乱、耦合度高。面对请求格式和处理逻辑的变化,没有进行全面的边界条件分析和测试,忽视了楼层有效性验证、队列操作顺序等细节问题。这让我明白,软件开发不仅要关注功能实现,更需注重设计的合理性、逻辑的严谨性以及充分的测试验证,避免因小失大。
心得
回顾三次 PTA 电梯调度题目的经历,成功与失败交织的过程让我对编程学习有了更深刻的理解。第一次题目要求将调度逻辑整合在单一程序中,我凭借对基础语法的熟悉顺利完成,这让我意识到扎实的语言基础是解决问题的前提。但第二次迭代要求拆分职责,引入多个类遵循单一职责原则时,我因对类设计理解不足而失败。这次教训让我明白,编程不仅是实现功能,更要注重代码的架构设计和可维护性,每个类的职责划分需要反复推敲。
第三次迭代新增乘客类并调整请求逻辑,尽管吸取了之前的经验,但在处理请求格式转换和队列动态管理时仍出现漏洞。这次失败让我深刻认识到,面对需求变化,不能仅依赖原有思路,必须全面梳理新的逻辑流程,同时要加强边界条件的测试。
这些经历让我明白,编程学习是一个不断试错和成长的过程。成功时不能自满,要思考如何优化代码;失败时也无需气馁,因为每一次错误都是发现自身不足的契机。从关注功能实现到重视代码质量,从解决单一问题到应对复杂需求,PTA 的每一道题目都推动着我在编程之路上不断前进。
浙公网安备 33010602011771号