题目5,6,7代码分析总结
一. 前言
在完成这三次题目集的过程中,我们始终围绕着面向对象编程知识展开实践。题目集5作为基础训练阶段,前四题着重于帮助我们恢复代码编写能力,并通过实践正则表达式来巩固这一技能,主要考察的是基础数学函数和逻辑结构的编写。从第五题开始,课程正式引入面向对象编程范式,以实现电梯调度算法中的LOOK算法为例,引导我们构建对象和类的概念,从而初步培养面向对象的编程思维。
题目集6则是面向对象思维的强化训练阶段。其中第一、二题的核心目标是深化我们对面向对象思维方式的理解,促使我们从根本上改变以往面向过程的解题思路,转而采用面向对象的设计模式来解决问题。第三题作为题目集5第五题的进阶版本,在难度和复杂度上都有显著提升,进一步巩固了我们的面向对象编程能力。
题目集7虽然题量相对较少,但难度却达到了最高水平。前两题继续围绕面向对象思维展开训练,而第三题则在题目集6第三题的基础上进行了更高层次的迭代开发,要求我们综合运用所学的面向对象编程知识来解决更加复杂的实际问题。这三次作业清晰地呈现出一条渐进式的学习路径:从基础代码能力的恢复,到面向对象思维的逐步建立,再到运用面向对象方法解决复杂问题的能力培养,帮助我们在编程技能上实现了稳步提升。
二.设计分析
题目5:
代码类的关系设计图:

使用SourceMonitor对代码进行分析:

代码分析:
(1).功能概述
这段代码模拟了一个电梯调度系统,通过面向对象的方式实现了电梯的运行和调度逻辑。用户可以通过输入指令来指定电梯的运行范围、乘客的上电梯请求和下电梯请求,电梯会根据一定的调度策略来完成这些请求。
(2).类的结构和功能
①.Elevate 类(电梯类)
属性
state:表示电梯的当前状态,如 "UP"(向上)、"DOWN"(向下)、"STOP"(停止)。
ad:表示电梯当前所在的楼层。
lowest 和 highest:分别表示电梯运行的最低楼层和最高楼层。
构造方法
初始化电梯状态为 "UP",当前楼层为 1。
方法
提供了 getState、setState、getAd、setAd、getLowest、setLowest、getHighest、setHighest 等 getter 和 setter 方法,用于获取和设置电梯的属性值。
②Passenger 类(乘客类)
属性
send:一个 ArrayList
receive:一个 ArrayList<String[]>,用于存储乘客的下电梯请求,每个元素是一个字符串数组,包含两个值:乘客下电梯的楼层和电梯的运行方向(如 "UP" 或 "DOWN")。
方法
aboard:用于从用户输入中读取乘客的上电梯和下电梯请求,并将它们分别存储到 send 和 receive 列表中。通过正则表达式匹配输入的格式,如 <数字> 表示上电梯请求,<数字,方向> 表示下电梯请求。
getOff:用于输出电梯的当前状态,包括当前楼层和运行方向。根据电梯的状态,输出不同的信息,如开门、关门或当前楼层和方向。
③Control 类(调度类)
属性
elevate:一个 Elevate 类型的对象,表示被调度的电梯。
方法
control:这是电梯调度的核心方法,根据乘客的上电梯和下电梯请求,控制电梯的运行。调度逻辑如下:
首先,检查 send 和 receive 列表是否为空,如果都为空,则调度结束。
然后,根据 send 和 receive 列表中的第一个请求,判断电梯需要运行的方向。如果两个请求的方向相同,则比较它们与当前楼层的距离,选择距离较近的请求作为目标;如果方向不同,则优先选择与当前电梯运行方向相同的请求。
调用 goTo 方法,将电梯移动到目标楼层,并在移动过程中不断输出电梯的状态。
在到达目标楼层后,根据请求类型(上电梯或下电梯)更新 send 或 receive 列表,移除已完成的请求。
goTo:用于将电梯移动到指定的目标楼层。在移动过程中,根据目标楼层与当前楼层的大小关系,更新电梯的运行方向("UP" 或 "DOWN"),并不断调用 Passenger 类的 getOff 方法输出电梯的实时状态。到达目标楼层后,将电梯状态设置为 "STOP",输出停止状态,然后恢复原来的运行方向。
(3). 主流程
在 Main 类的 main 方法中,程序的主流程如下:
初始化一个 Scanner 对象,用于读取用户输入。
初始化一个 Elevate 对象,表示电梯,并通过用户输入设置电梯的最低楼层和最高楼层。
初始化一个 Passenger 对象,通过调用其 aboard 方法读取乘客的上电梯和下电梯请求。
输出电梯的初始状态,当前楼层为 1,方向为 "UP"。
创建一个 Control 对象,调用其 control 方法,将电梯对象和乘客的请求列表传递给调度类,开始电梯的调度过程。
(4). 代码的优点
面向对象设计:代码采用了面向对象的编程思想,将电梯、乘客和调度逻辑分别封装成不同的类,每个类都有明确的职责,使得代码结构清晰,易于理解和维护。
模块化:通过将不同的功能封装在不同的类和方法中,实现了代码的模块化。例如,电梯的状态管理、乘客请求的处理和电梯的调度逻辑分别由不同的类或方法负责,方便了代码的复用和扩展。
输入输出处理:Passenger 类的 aboard 方法通过正则表达式对用户输入进行格式校验和解析,能够灵活地处理乘客的上电梯和下电梯请求,提高了程序的健壮性。同时,getOff 方法能够实时输出电梯的状态,方便用户了解电梯的运行情况。
(5). 代码的不足之处
调度算法的局限性:虽然代码实现了一种简单的电梯调度逻辑,但这种调度算法可能并不是最优的。在实际的电梯调度中,可能需要考虑更多的因素,如电梯的负载、乘客的等待时间、电梯的运行效率等,以实现更合理的调度策略。
异常处理不足:代码中对输入数据的合法性检查不够全面。例如,在 aboard 方法中,虽然对输入的格式进行了正则表达式匹配,但没有对输入的楼层范围进行校验,可能会导致用户输入超出电梯运行范围的楼层,从而引发程序错误。此外,在 Control 类的 control 方法中,也没有对可能出现的异常情况进行处理,如 send 和 receive 列表为空时的处理逻辑不够完善。
代码的可扩展性有限:如果需要增加新的功能,如支持多部电梯的调度、考虑电梯的优先级等,代码的修改量可能会比较大。这主要是因为代码的结构和逻辑在一定程度上是针对当前的简单场景设计的,没有充分考虑到未来可能的扩展需求。
变量命名不够规范:部分变量的命名不够直观,如 ad、send、receive 等,可能会让阅读代码的人难以理解其含义。建议使用更具描述性的变量名,以提高代码的可读性。
题目6:
代码类的关系设计图:

使用SourceMonitor对代码进行分析:

代码分析:
本次代码在多个方面表现出明显的优势:
①将乘客的请求明确划分为内部请求(上电梯)和外部请求(下电梯),逻辑更加清晰易懂。
②符合单一职责原则:与第一段代码相比,第二段代码将输入处理和请求管理分离,避免了像 Passenger 类那样功能过于分散的问题。
③调度逻辑细致:在处理请求时,第二段代码更加细致,能够更好地应对复杂的请求场景,从而提供更精准的调度。
④模块化设计:通过 ExternalRequest 类封装外部请求,第二段代码实现了更高的模块化程度,这使得代码更易于扩展和维护。
⑤合理运用设计模式:第二段代码巧妙地运用了工厂模式和策略模式的思想,这不仅提升了代码的可扩展性,还增强了其可维护性。
⑥出色的可扩展性:第二段代码在应对未来需求变化方面展现出更强的适应性,能够灵活地应对各种复杂业务需求。
⑦良好的可读性:得益于规范的变量命名和合理的类划分,第二段代码在可读性方面表现出色,这将极大地方便后续的代码维护和扩展工作。
相比之下,第一段代码存在一些不足之处:
①设计不合理:第一段代码的设计不够合理,导致其扩展性和可读性较差,这可能会给未来的维护和扩展带来困难。
②合法性检查不足:第一段代码对输入数据的合法性检查不够全面,这可能会导致程序在运行过程中出现错误。
③尽管第一段代码也能实现基本功能,但在设计、可扩展性、可读性和数据合法性检查等方面都存在明显的不足。
题目7:
代码类的关系设计图:

使用SourceMonitor对代码进行分析:

改进建议:
代码性能优化:
在请求处理逻辑中,可以考虑使用更高效的数据结构和算法。例如,在判断是否有某个方向的请求时,可以使用更高效的查找算法,或者将请求队列按照楼层顺序进行排序,这样可以减少查找和判断的时间复杂度。同时,在处理请求时,可以采用多线程技术,提高请求处理的并行性,特别是在多电梯调度的场景下,多线程可以显著提升系统的性能。
代码结构优化:
对于一些复杂的方法,如 processRequests 和 move 方法,可以进一步拆分,将不同的功能模块封装成独立的方法,提高代码的可读性和可维护性。例如,可以将方向判断、请求处理、电梯移动等功能分别封装成不同的方法,使得代码结构更加清晰,便于后续的修改和扩展。
三、踩坑心得
本部分对每次题目集提交代码出现的问题和心得进行总结
1.对于电梯调度算法的错误理解:当我第一次看到这么长的题目后,一时间不知道怎么下手,然后对于题目中描述的算法也是不知所措。过了几天老师在群里说了这个电梯的算法是简易版的Look算法。然后我就去了解了一下Look算法的内容,其描述是:考虑完当前方向才会换方向。再加上样例中电梯的方向只改变了一次,所以我就以为题目算法只要让电梯变化一次方向就可以处理完所有的电梯内外请求,于是我便开始写代码,写完后发现测试样例能过,但是提交了又过不去测试点。然后我就不断地修改、提交、修改、提交,提交了40多次回应我的只有绿绿的答案错误。后来才发现是算法不沾边,做了两天的无用功。所以也警示我们一定要理解好题目意思,设计好算法再开始写代码。
2.LinkedList中方法的错误使用:在使用LinkedList中的getFirst方法来取出电梯内部请求队列头部和电梯外部请求来判断电梯的运行方向的时候没有考虑到队列可能为空的情况,导致提交了几次都显示我非零返回。上网了解后才发现,使用getFirst方法的时候如果链表为空的话就会出现非零返回的错误。
3.电梯运行的逻辑错误:某次提交的过程当中显示我运行超时,仔细分析后发现是处理过程的时候,先判断电梯方向后检查是否停靠,然后控制电梯运行到下一层。但是这种运行逻辑,当上升方向请求运行完了后,外部请求头部的下降的楼层大于上升的楼层时,就会无法清除掉这个外部队列头部请求,导致电梯一直在停靠楼层上下运动,进而运行超时。
4.正则表达式的错误使用:在主方法里使用正则表达式来解析输入的数据时由于当时对正则表达式的理解还不够深刻,在解析外部请求的时候,无法将正确的数据给读取进来。这个问题当时困扰了我很久,我也不断地在哪思考问题所在,最后发现我在定义表达式模式的时候少打了一个“,”导致无法正确的去匹配外部请求数据。
五、总结
通过这三次迭代性题目集的综合性学习,我收获到了很多,首先,理解题目电梯调度的算法并且成功用Java编程实现出来,使我的逻辑思维和编程能力有了大幅度的提升。然后在不断编写和调试代码的过程中, 对于Java的语法掌握、正则表达式的灵活应用和面向对象的程序设计有了全方面的理解和提升,尤其是对于类的设计以及对类间关系的理解这一块,在通过第一个题目集迭代到第二个题目集解决电梯类职责过多的问题的训练,现在我对于类设计的遵循单一职责原则和类间关系的设计有了更加深刻的认识。但还是需要对可扩展性的设计结构进行深入的研究和学习。
浙公网安备 33010602011771号