第一次blog作业
(1)前言
在经过几周的Java语言的学习后,我深刻意识到了其相对于C语言的更高难度和带来的更多挑战。这几周作业中最具有挑战性的内容的是三次单部电梯调度程序设计,通过对于这三次作业的分析将有助于我掌握相关的知识。
第一次作业:第一次作业是这三次作业中最容易的一次,本次作业没有要求有类的设计或是其他的算法要求,但是包含了许多知识点如枚举,数据的封装,正则表达式和LinkedList的使用等。这些基础内容为后续学习打下了坚实基础,让我初步领略到 Java 编程的丰富性与灵活性。
第二次作业:相比于第一次作业,增加了对于java程序的类设计要求和一些要求,要求我们根据类图来对程序进行设计,以达成满足面向对象程序设计的单一职责原则(SRP)(其他的暂时未学习)。这里要求我们要能够更加深入理解类之间的关系,能够将不同功能拆分到独立类中,保证每个类只负责单一职责,同时减少类之间不必要的交互,提升代码的可维护性与扩展性。体现了对于面向对象程序设计思维的初步考察。
第三次作业:在前两次作业的基础上,要求增加(类设计-迭代)和一些特定要求,相比与前两次有了更加具体的要求。它不但要保证新增功能与原有代码的兼容性,又要设计迭代的类,就像是模拟未来可能遇到到具体设计要求,强化了我们在复杂需求下优化代码的实践能力以及考验源代码设计(第二次)是否满足单一职责原则(SRP)和代码是否具有一定的可拓展性。进一步的考察并规范了我们的面向对象程序设计思维。
总结:三次作业通过逐步提升难度的方法使我们逐步学习和掌握相关的知识,并且还通过逐渐对我们的面向对象设计的过程进行的过程进行必要规范,提高了我们程序设计过程的高效性和专业性。让我们能更好的获取和巩固相关的知识,达到了高效教授面向对象程序设计课程的目的。
(2)设计与分析
第一次题目如下:设计一个电梯类,具体包含电梯的最大楼层数、最小楼层数(默认为1层)当前楼层、运行方向、运行状态,以及电梯内部乘客的请求队列和电梯外部楼层乘客的请求队列,其中,电梯外部请求队列需要区分上行和下行。
电梯运行规则如下:电梯默认停留在1层,状态为静止,当有乘客对电梯发起请求时(各楼层电梯外部乘客按下上行或者下行按钮或者电梯内部乘客按下想要到达的楼层数字按钮),电梯开始移动,当电梯向某个方向移动时,优先处理同方向的请求,当同方向的请求均被处理完毕然后再处理相反方向的请求。电梯运行过程中的状态包括停止、移动中、开门、关门等状态。当电梯停止时,如果有新的请求,就根据请求的方向或位置决定移动方向。电梯在运行到某一楼层时,检查当前是否有请求(访问电梯内请求队列和电梯外请求队列),然后据此决定移动方向。每次移动一个楼层,检查是否有需要停靠的请求,如果有,则开门,处理该楼层的请求,然后关门继续移动。
使用键盘模拟输入乘客的请求,此时要注意处理无效请求情况,例如无效楼层请求,比如超过大楼的最高或最低楼层。还需要考虑电梯的空闲状态,当没有请求时,电梯停留在当前楼层。
请编写一个Java程序,设计一个电梯类,包含状态管理、请求队列管理以及调度算法,并使用一些测试用例,模拟不同的请求顺序,观察电梯的行为是否符合预期,比如是否优先处理同方向的请求,是否在移动过程中处理顺路的请求等。为了降低编程难度,不考虑同时有多个乘客请求同时发生的情况,即采用串行处理乘客的请求方式(电梯只按照规则响应请求队列中当前的乘客请求,响应结束后再响应下一个请求),具体运行规则详见输入输出样例。
输入格式:
第一行输入最小电梯楼层数。
第二行输入最大电梯楼层数。
从第三行开始每行输入代表一个乘客请求。
• 电梯内乘客请求格式:<楼层数>
• 电梯外乘客请求格式:<乘客所在楼层数,乘梯方向>,其中,乘梯方向用UP代表上行,用DOWN代表下行(UP、DOWN必须大写)。
• 当输入“end”时代表输入结束(end不区分大小写)。
第一次作业的分析:
遗憾的是本次作业我最终提交的代码总是会运行超时,导致无法在题目集输出答案。首先参考SourceMontor的生成报表内容可以观察代码的相对Avg Complexity(平均复杂度)达到了5.50,经过查询我知道这是一个复杂性较高的代码,在可读性方面它容易造成以下问题:(1)理解困难:复杂代码往往包含大量嵌套结构、逻辑分支和晦涩的算法实现。在阅读时,往往难以快速理清代码逻辑,理解代码的意图和功能实现方式(这里建议先用相应的软件进行尝试运行代码)。(2)运行效率低:过于复杂的算法、过多的条件判断和方法调用等,可能导致程序运行时消耗更多的 CPU、内存等资源,降低程序的运行效率(可能会像我一样运行超时)。(3)代码调试和审查困难:我们在调试和审查中面对复杂代码很难在短时间内发现潜在问题,代码规范问题、逻辑漏洞等,并且如果代码报错,一个个修改错误很可能造成更多错误(属实难蚌,在编译器里错误多的时候看起来要把眼睛看爆了尤其是编译器黑底白字的,建议把编译器的界面换成白底黑字)。也可能还有其他问题,在此处就不多举例了。
作为对比,我这里将给出另外一个代码的SourceMontor的生成报表内容:
相比于上面的代码,这里的代码虽然Lines(代码行数)的数值从202增加到218(代码量有所增长),Statements(语句数量)从123变到154语句数量增多,还有部分数值的升降,但是它的Avg Complexity(平均复杂度)却只有3.00,这表明了它具有比前者更高效,更可读,更据拓展性等特点。
第二次作业大体上与第一次相似但要处理如下情况:
乘客请求楼层数有误,具体为高于最高楼层数或低于最低楼层数,处理方法:程序自动忽略此类输入,继续执行
乘客请求不合理,具体为输入时出现连续的相同请求,例如<3><3><3>或者<5,DOWN><5,DOWN>,处理方法:程序自动忽略相同的多余输入,继续执行,例如<3><3><3>过滤为<3>
第二次作业分析:
以上为本次作业的类设计图,它包含了以下的类:Elevator类,Controller类,ExternalRequest类,RequestQueue类, 枚举类和Main类。
它们分别承担以下功能:
Elevator类:
模拟电梯实体及其行为状态。属性记录电梯当前楼层、运行方向、状态、可到达的最大和最小楼层 。方法实现电梯实例创建、状态和楼层信息的获取与设置,以及判断楼层有效性等功能。
Controller类:充当电梯控制系统的核心角色。通过其方法处理电梯请求,确定运行方向,控制电梯移动、开关门等操作 ,协调电梯与请求队列间的交互。
ExternalRequest类:
用于表示外部对电梯的请求。属性记录请求楼层和方向,方法提供获取这些请求信息的功能。
RequestQueu:
负责管理电梯请求队列。维护内部请求(电梯内乘客指令)和外部请求列表 ,通过方法实现对请求的添加、获取等操作,为 Controller类提供请求管理功能,使电梯有序处理各类请求。
枚举类:
Direction 枚举类:定义电梯运行方向(向上、向下、空闲),为 Elevator 类等涉及方向判断和设置。
tate 枚举类:界定电梯状态(移动中、停止) ,用于标识 Elevator 类的不同状态。
Main类:
作为程序入口,包含 main 方法。程序启动时首先执行该方法,负责初始化系统、创建必要对象(如 Elevator、Controller 等实例),并启动电梯系统运行逻辑。
要完成第二次作业首先要能够读懂类图。对与我们来说,类图是告诉我们要完成的结果的框架,用老师的话来说就是修建筑时要用到的图纸,只有按照图纸来完成建造才能满足甲方的要求,这个道理在面向对象程序设计也是共通的,我们只有能读懂类图才能准确完成要求,不能想当然的按照自己的想法去完成项目,这样既不符合别人的要求而且效率也不一定会高。所以对我们应该先看类图而构思代码,而不能反着来,就像射箭一样不能先射箭而后才画靶子。颠倒因果只会得到一地鸡毛。
代码的SourceMontor的生成报表内容如下:

复杂度还是比较低的水准(只可惜实在题目集结束后才改完的),而一开始的源代码我会在下一环节告诉你们没有用SourceMontor的生成报表内容的原因。
(3)踩坑心得
1 枚举类建议放在代码的开始位置。因为我在写的过程中把它放在某个函数类,导致调用时非常麻烦,要反复调用那个类,并且有时候写着写着调用时忘了引用那个类,导致出现一大堆报错,所以为了方便起见,我建议将枚举类建议放在代码的开始位置(其实是还怕写到后面忘记写了,还有枚举的不同常量用逗号隔开)
2 设计代码时尽量早点考虑边界。比如在第二次作业里的Elevator类虽然写了判断楼层是否在最值之间,但是没在Main类写判断最大值和最小值大小的方法,导致出现代码无法继续运行的情况.还有在接收错误数据时,应当增加让重新输入的代码,不然调试时不小心按错键就完蛋了,又要重新运行一遍代码和重新输入数据.
3 在编译器Idea中如果仅用创建的一个public类来对应粘贴的代码(其中含有多个类)就可能造成类的重复定义而无法使用调试功能(图是其他的代码)

所以我建议调试时要么分离其中的类要么干脆将其中的其他类包含进public。
4 一开始直接开始写代码而不看类图的我是**。(大家一定要看类团啊)
(4)改进建议
1如果用户输入的最低楼层minFloor大于最高楼层maxFloo,r电梯的isValidFloor()方法会错误地认为所有楼层均无效导致程序无法正常运行
可以在Main类增加
if (minFloor > maxFloor) {
int temp = minFloor;
minFloor = maxFloor;
maxFloor = temp;
}来判断
2 如果电梯在最高楼层收到上行请求(已过滤),但代码未显式限制移动范围
可以在Controller类move方法中加入
if (elevator.getDirection() == Direction.IDLE) return;
int nextFloor = getNextFloor();
nextFloor = Math.min(nextFloor, elevator.getMaxFloor());
nextFloor = Math.max(nextFloor, elevator.getMinFloor());
(5)总结
学到的核心知识点:
1 类与对象:通过 Elevator,Controller,RequestQueue 等类的划分,实现高内聚低耦合的设计。
2 枚举类型:使用 Direction 和 State 枚举明确状态,提升代码可读性和安全性。
3 队列管理:利用 LinkedList 或 PriorityQueue 合并请求,确保按方向分层处理。
4 正则表达式:验证输入格式(如 ❤️, UP>)的合法性。
5 边界检查:确保楼层在 minFloor 和 maxFloor 范围内等
进一步需要学习的:
1 对于LinkedList(链表)的应用还应该继续学习。
2 LOOK算法:动态调整方向,避免电梯走到端点楼层.
3 电梯状态的修改:电梯每次开,关门的状态和运动方向应及时修改。
4 电梯的调度:优化电梯计算到目的地的算法,是它尽量移动尽量短和代码尽量简洁。
浙公网安备 33010602011771号