南昌航空大学-软件学院-24201435-袁芳驰-第一次blog作业

前言:

这个博客是对先前三次大作业的总结及分析,从第一次接触Java已经将近一个半月了没想到才过去这点时间,学期刚开始开始写程序设计的课设第一次写较大的代码我感受到了这门课的不易,也激励我一定要在专业课上多花时间对比上个学期学习的C语言,我认为java更加方便,一些简单的函数我可以直接使用类中的各种方法直接实现属实方便。在这一个月的java学习过程中,刚开始时出的题目集比较简单用来熟悉Java语法,第一次觉得有点困难是在题目集四的日期类设计但还是花了些许时间成功解决了,让我真正感受到难度的是之后题目集里让我念念不忘的单部电梯调度程序,当我第一次面对它是我的表情完美契合老人地铁手机的表情包完全不知道咋下手但还是硬着头皮思考了下电梯的运行逻辑但半天还是没弄懂之后成功向学霸取经稍微懂了点,但对我来说任然是个艰巨的任务话不多说直接开始分析总结吧。

1.知识点:

在三次的题目集中我学到了许多,包括对Java语法的熟悉与掌握,获取字符串的长度 length() 方法字符串查找indexOf()获取charAt()substring():用于截取字符串的一部分replace():用于替换字符串中的指定字符或字符序列trim():去除字符串首尾的空白字符。还有集合里的size(),get(),remove(),add()等等。除开对这些方法的运用以及理解还有对类的设计调用这是设计程序最重要的一部分了也是区别面向结果编程与面向对象编程最大的区别了
这些知识要点不仅增强了我对 Java 语言的理解,更提升了我的编程实践能力。在后续学习中,我会继续巩固这些知识,深入探索 Java 更复杂的特性,力求让自己的编程水平迈向新高度。

2.题量:

由于存在电梯单步调度设计这样的“王炸”,题量比较小。

3.难度:

除开电梯单步调度设计其余的题目都比较简单,几乎都是以设计类为主体没啥复杂的题目,所以题目集除开最后一题都比较简单。
设计与分析

第一次作业:

总共五题第一题与第二题主要是考察语法以及熟悉一下Java类的设计,三四题就是向我们介绍了一下正则表达式,前四题难度都不大就不介绍了,第五题是单部电梯调度程序设计,让我们输入一系列的数据包含最低楼层/最高楼层内部请求以及外部请求,其中内部请求仅包含目标楼层,而外部请求包含所在楼层以及请求方向(“UP”或“DOWN”)根据电梯运动方向判断是否该停下,当电梯向某个方向移动时,优先处理同方向的请求,当同方向的请求均被处理完毕然后再处理相反方向的请求,每次移动一个楼层,检查是否有需要停靠的请求,如果有,则开门,处理该楼层的请求,然后关门继续移动。然后输出电梯的运行结果。

单部电梯调度程序设计

题目:

设计一个电梯类,具体包含电梯的最大楼层数、最小楼层数(默认为1层)当前楼层、运行方向、运行状态,以及电梯内部乘客的请求队列和电梯外部楼层乘客的请求队列,其中,电梯外部请求队列需要区分上行和下行。
电梯运行规则如下:电梯默认停留在1层,状态为静止,当有乘客对电梯发起请求时(各楼层电梯外部乘客按下上行或者下行按钮或者电梯内部乘客按下想要到达的楼层数字按钮),电梯开始移动,当电梯向某个方向移动时,优先处理同方向的请求,当同方向的请求均被处理完毕然后再处理相反方向的请求。电梯运行过程中的状态包括停止、移动中、开门、关门等状态。当电梯停止时,如果有新的请求,就根据请求的方向或位置决定移动方向。电梯在运行到某一楼层时,检查当前是否有请求(访问电梯内请求队列和电梯外请求队列),然后据此决定移动方向。每次移动一个楼层,检查是否有需要停靠的请求,如果有,则开门,处理该楼层的请求,然后关门继续移动。
使用键盘模拟输入乘客的请求,此时要注意处理无效请求情况,例如无效楼层请求,比如超过大楼的最高或最低楼层。还需要考虑电梯的空闲状态,当没有请求时,电梯停留在当前楼层。
请编写一个Java程序,设计一个电梯类,包含状态管理、请求队列管理以及调度算法,并使用一些测试用例,模拟不同的请求顺序,观察电梯的行为是否符合预期,比如是否优先处理同方向的请求,是否在移动过程中处理顺路的请求等。为了降低编程难度,不考虑同时有多个乘客请求同时发生的情况,即采用串行处理乘客的请求方式,具体运行规则详见输入输出样例。

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

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

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

分析:

第五题是单部电梯调度程序设计,让我们输入一系列的数据包含最低楼层/最高楼层内部请求以及外部请求,其中内部请求仅包含目标楼层,而外部请求包含所在楼层以及请求方向(“UP”或“DOWN”)根据电梯运动方向判断是否该停下,当电梯向某个方向移动时,优先处理同方向的请求,当同方向的请求均被处理完毕然后再处理相反方向的请求,每次移动一个楼层,检查是否有需要停靠的请求,如果有,则开门,处理该楼层的请求,然后关门继续移动。然后输出电梯的运行结果。我将我代码里的核心板块概括为以下内容
1.输入处理:获取最小楼层 min、最大楼层 max 以及一系列电梯请求。对输入的请求字符串进行解析,依据请求类型将楼层和方向信息添加到 Elevator 类的相应列表里。
2.请求添加:依据请求类型(内部请求、外部请求),把请求信息添加到对应的列表中。
3.请求优先级判断:根据电梯当前运行方向,判断内部请求和外部请求的优先级。
4.电梯移动:检查当前所在楼层是否是目标楼层,如果是就停下开门,不是就按照当前方向向下一个楼层移动。
5.方向更新:当前的方向的请求处理完后,电梯更换方向。
6.请求处理:遍历内部请求和外部请求,寻找与电梯当前运行方向相同的请求。

历程:

开始时进行分析与思考时我搞错了电梯的运行逻辑,在我的印象里电梯当外部有人请求时会直接开门然后乘客在电梯内按键,但在题目里是先忽略反方向的请求直接前往符合电梯运行方向的楼层,还有我的另一个错误是因为这道题它只给了一个样例我无法将电梯的运行逻辑是对所有请求进行分析丛而规划路线,但之后经过老师指出我才知道电梯是处理完当下请求在处理下个请求的,知道这个消息时我看着我那极其混乱想到哪写到哪的代码我觉得在这上面进行更改的难度实在太大,于是我下定决心重头开始。有了前车之鉴我决定先想好整个运行逻辑设计好一些方法在编写,我将除开请求输入之外的功能包括确定方向,电梯移动等方法全都移入了电梯类当中。在之后我开始思考该使用什么方法来操作请求队列,因为老师开始说不能使用集合框架,我决定使用链表来操作,开始时我以为不可以使用Arraylist于是请教同学后我开始试着构建一个链表但看到老师发的信息后才知道原来可以使用Arraylist于是便修改了代码。这次的经历属实一波三折,从开始到结束最后一天真的想过放弃算了,一道题而已没必要搞得自己这么痛苦,但始终无法做到放弃就是不甘心,于是就一直写直到最后一天才改出来了。

1).类图分析

解释:该程序包含两个类Main以及Elevator,其中Main负责的是的输入的进行以及简单的处理将外部条件分为楼层以及方向

Elevator 类主要围绕电梯的运行逻辑展开。它会接收来自 Main 类处理后的楼层和方向信息,在此基础上,实现电梯的各种功能。例如,根据接收到的楼层信息,计算电梯的运行路径,判断是否需要停靠;依据方向信息,决定电梯是向上运行还是向下运行,输出电梯的运行结果
看到这个类图是真的给我已经晕了,我当时按照题目就创建了两个类将所有功能挤在一个类当中将所有功能挤在一个类当中,这就好比把所有工具都一股脑塞进一个小口袋,看似方便却乱成一团。里面的各种调度也很复杂。现在回头看,这样的设计完全没有考虑到代码的可维护性和扩展性。如果项目规模进一步扩大,功能不断增加,这个类就会像一个不堪重负的容器,随时可能崩溃。我深刻认识到,合理的类结构设计是多么重要,之后一定要遵循设计原则,对功能进行合理拆分,让代码更加简洁、高效、易于维护。

2).SourceMontor的生成报表


根据 SonarQube 的代码检测

1.代码复杂度方面:代码的圈复杂度偏高,在业务逻辑处理中,过度使用嵌套的 if - else 语句以及多层循环,导致部分方法的复杂度超出合理范围。这不仅使代码可读性变差,而且在维护和扩展时容易引入新的问题,后续需要对复杂逻辑进行拆分和优化。
2.代码可维护性方面:2.代码注释较少,不利于阅读和修改。
3.代码正确性方面:经过全面检测,代码在功能实现上没有明显的逻辑错误,能够按照预期完成各项业务功能。但鉴于前面提到的复杂度和可维护性问题,仍需进行系统性优化,以提升代码整体质量。
4.代码块直方图:从图中可以看出在深度为 1、3、4 .2 的代码块也包含了相对较多的语句,而深度为 0 以及深度大于 5 的代码块所包含的语句数量较少。这表明代码中完全没有嵌套的简单代码块占比较小,同时深度过高的复杂代码块也不多,但存在不少 2 - 4 层嵌套的代码块,整体代码的嵌套情况较为集中在中等深度范围。

总结:

这次的经历属实一波三折,从开始到结束最后一天真的想过放弃算了,一道题而已没必要搞得自己这么痛苦,但始终无法做到放弃就是不甘心,幸运的是成功在最后一天改出来了。这次血与泪的教训让我铭记了以后必须遵循一下步骤一、对题目进行全面分析,搞懂题目的核心要求与隐含条件。以往总是匆匆下笔,这次才明白,磨刀不误砍柴工。二、运用面向对象编程思想进行系统设计。将问题域中的实体抽象成类,梳理清楚类与类之间的关系确定每个类的属性与方法,确保职责单一且清晰。三、做好代码的规划与架构搭建。明确各个类的结构与交互流程,再着手编写代码。按照模块划分,逐步实现功能,每完成一个小模块就进行单元测试,及时发现并修正问题。四、重视代码的可读性与可维护性。编写代码时,规范命名变量与方法,添加必要的注释,让代码逻辑一目了然。五、保持耐心与韧性。

第二次作业

总共三题,第一题是点与线的类设计没啥难点就不介绍了,第二题是汽车风挡玻璃雨刷问题(类设计)只要把题目意思搞懂了就很明了了也不难,第三题是对第一次电梯调度的迭代,我觉得比第一次轻松一些。

题目:

对之前电梯调度程序进行迭代性设计,目的为解决电梯类职责过多的问题,类设计要求遵循单一职责原则(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

分析:

这次要求是对第一次的迭代,有一下修改点,一是增加对错误格式(不符合楼层范围,乘客请求不合理,具体为输入时出现连续的相同请求,例如<3><3><3>或者<5,DOWN><5,DOWN>)前者程序自动忽略此类输入后者程序自动忽略相同的多余输入,二是解决电梯类职责过多的问题设计以下电梯类、乘客请求类、队列类以及控制类。

历程:

在开始没看到题目时我以为又会很难,但在我浏览后感觉没有那么难,于是我决定先增加请求类在其中增加对请求检验修改的功能,在完成后我开始规划该如何将先前的代码放入相对应的类,在有了想法后我便开始了修改,经过一段时间的修改后代码便修改完毕了。

介绍:

错误输入检验:

关于错误输入我是这样处理的:在main中,我先依据输入字符串是否包含逗号来分离外部请求与内部请求。
分离后,对两类请求分别进行检测。针对内部请求,直接调用Request类的checkFloor方法,尝试从请求字符串中提取楼层号,并判断该楼层号是否处于预先设定的min和max楼层范围之间。一旦提取过程中出现异常,如字符串无法转换为数字,或者提取出的楼层号超出范围,都将判定该内部请求为错误输入。
对于外部请求,首先,检查请求字符串按逗号分割后的部分数量是否为 2,若不为 2 则直接判定格式错误。接着,对分割后的第一部分提取楼层号,同样利用checkFloor方法判断楼层是否在有效范围内,若不满足则提示楼层超出范围错误。最后,检查分割后的第二部分方向信息,若方向不是UP或DOWN,则提示方向错误。
在收集完所有请求后,我调用 Request 类的 deleteSameRequest 方法来处理重复请求。该方法会遍历请求列表,如果发现相邻的两个请求内容相同,就会将重复的请求删除,只保留一个。具体实现是先创建一个新的结果列表,将第一个请求添加进去,然后从第二个请求开始依次与前一个请求比较,若不相同则添加到结果列表中。最后清空原请求列表,并将处理后的结果列表内容重新添加回去。

类设计:

我将电梯类划分为了四个类请求类 队列类 电梯类 控制类
请求类:负责处理和管理乘客的电梯请求,包括检查请求的合法性、提取楼层信息、转换请求格式以及删除重复请求。
控制类:控制电梯的运行逻辑,根据内部请求和外部请求的情况决定电梯的移动方向和目标楼层,并处理请求的优先级。
队列类:用于存储和管理电梯的内部请求和外部请求,提供添加请求和获取请求列表的方法。
电梯类:负责模拟电梯的移动过程和输出电梯的状态信息,如当前楼层和运行方向。

1).类图分析

解释:

Control 类:负责电梯运行控制逻辑。持有 Lift 类实例和 Queue 类实例 。通过构造函数传入楼层范围及请求队列等参数,包含一系列方法如 process 处理电梯运行流程、compareFloors 比较楼层等,用于处理电梯运行方向、请求调度等复杂逻辑。
Lift 类:表示电梯实体。有楼层范围属性、当前楼层、运行方向等属性。通过构造函数设置楼层范围,具备 moveToFloor 移动到目标楼层、getCurrentFloor 获取当前楼层等方法,用于控制电梯的实际运行动作。
Queue 类:用于管理请求队列。包含内部请求列表和外部请求列表 。有构造函数初始化队列,以及 addRequest 添加请求、getInternalRequest 获取内部请求、getExternalRequest 获取外部请求等方法,负责对电梯的各种请求进行存储和管理。
Request 类:处理请求相关逻辑。有楼层范围属性以及内部、外部请求列表 。构造函数设置楼层范围,具备 checkRequest 检查请求合法性、reformRequest 调整请求、deleteSameRequest 删除重复请求等方法,对电梯请求进行预处理和管理。
Main 类:程序入口类。包含 main 方法,作为程序启动的起点,协调其他类的初始化和运行,负责请求输入。

2).SourceMontor的生成报表

根据 SonarQube 的代码检测

1.代码复杂度方面:代码的圈复杂度偏高,在业务逻辑处理中,过度使用嵌套的 if - else 语句以及多层循环,导致部分方法的复杂度超出合理范围。这不仅使代码可读性变差,而且在维护和扩展时容易引入新的问题,后续需要对复杂逻辑进行拆分和优化。
2.代码可维护性方面:代码注释较少,不利于阅读和修改。
3.代码正确性方面:经过全面检测,代码在功能实现上没有明显的逻辑错误,能够按照预期完成各项业务功能。但鉴于前面提到的复杂度和可维护性问题,仍需进行系统性优化,以提升代码整体质量。
4.代码块直方图:从图中可以看出在深度为 1、3、4 .2 的代码块也包含了相对较多的语句,而深度为 0 以及深度大于 5 的代码块所包含的语句数量较少。这表明代码中完全没有嵌套的简单代码块占比较小,同时深度过高的复杂代码块也不多,但存在不少 2 - 4 层嵌套的代码块,整体代码的嵌套情况较为集中在中等深度范围。
5.方法复杂度分布:从列出的最复杂方法明细来看,Control 类中的方法复杂度普遍较高。如 Control.compareFloors() 复杂度达到 11,拥有 12 条语句且最大深度为 4 。这意味着在该类的业务逻辑处理中,存在较为复杂的条件判断或操作组合。而像 Request 类中的部分方法,如 Request.checkRequest() 复杂度为 4 ,相对来说复杂度处于中等水平。
6.代码行数与语句数关系:文件总行数为 320 行,而语句数为 222 条。说明代码中存在一定比例的非执行语句,如声明语句等。虽然这是正常情况,但结合代码复杂度来看,较多的非执行语句可能在一定程度上掩盖了逻辑结构,后续可考虑优化代码结构,使逻辑语句更加清晰突出。
7.类与方法数量关系:项目中共有 3 个类和接口,平均每个类拥有 9.67 个方法。这反映出类所承担的职责相对较多,可能存在功能过于集中的问题。

总结:

第二次作业总的来说没有第一次时的那么难,先增加对错误请求的检测与处理再对先前的方法进行划分即可,在完成划分类后,我发现改进后的代码相比之前有了以下优点1.代码更加易读,相比之前将所有方法挤在一个类当中,有了职责划分后,代码明显更加易读这也启示我之后一定要提前规划好类的设计。2.修改更方便。3.方便代码审查。这也提醒我今后要着手编写代码前,投入更多时间和精力进行系统的架构设计与类的规划。深入分析需求,明确各个功能模块的职责边界,提前绘制类图等设计文档,确保代码结构从源头就具备良好的逻辑性和可扩展性,避免在开发过程中因结构不合理而频繁返工。

第三次作业

总共三题,第一题是销售步枪问题类设计没啥难点就不介绍了第二题运用蒙特卡罗方法求圆周率,相比第一题,其难度有所提升,这道题的复杂性体现在多个方面。一方面,要理解蒙特卡罗方法的原理,并将其转化为具体的编程实现逻辑,需要对概率统计知识和编程技巧有较好的结合运用能力。另一方面,在实际编程中,如何高效地生成随机点、准确判断点的位置,以及处理大量数据时保证程序的性能和准确性,都是需要解决的问题。第三题是对电梯的迭代。

题目:

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

乘客请求输入变动情况:外部请求由之前的<请求楼层数,请求方向>修改为<请求源楼层,请求目的楼层>
对于外部请求,当电梯处理该请求之后(该请求出队),要将<请求源楼层,请求目的楼层>中的请求目的楼层加入到请求内部队列(加到队尾)
注意:本次作业类设计必须符合如上要求(包含但不限于设计电梯类、乘客类、队列类以及控制类),凡是不符合类设计要求此题不得分,另外,PTA得分代码界定为第一次提交的最高分代码(因此千万不要把第一次及第二次电梯程序提交到本次题目中测试)。

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

电梯内乘客请求格式:<楼层数>
电梯外乘客请求格式:<请求源楼层,请求目的楼层>,其中,请求源楼层表示乘客发起请求所在的楼层,请求目的楼层表示乘客想要到达的楼层。
当输入“end”时代表输入结束(end不区分大小写)。
输出格式:
模拟电梯的运行过程,输出方式如下:

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

分析:

这次电梯调度程序迭代设计主要有以下修改要点:
类结构调整:新增乘客类,取消原乘客请求类,通过设计电梯类、乘客类、队列类以及控制类,遵循单一职责原则,解决原电梯类职责过多的问题,使各功能模块职责划分更加清晰。
请求格式变更:外部请求格式从 <请求楼层数,请求方向> 修改为 < 请求源楼层,请求目的楼层 >,更贴合实际乘坐电梯的场景需求。同时规定电梯处理完外部请求后,需将请求目的楼层加入内部请求队列。

思路:

在看到题目后我决定先从请求改进方面开始修改,我的思路是将 < 请求源楼层,请求目的楼层 >拆分比较楼层从而得出方向然后将< 请求源楼层,请求目的楼层 >分解成<请求楼层数,请求方向> ,<请求目的楼层>将其添加到队列当中这样我就可以不用修改太多代码,按照要求我将<请求目的楼层>添加到一个链表中在遍历完所有请求后将<请求目的楼层>的链表添加到队尾,之后经过测试发现结果正确,便开始进行类修改.

介绍:

外部请求处理:

我将输入的请求传参到乘客类当中先对请求经行检验请求是否合理并将外部请求拆分为<请求楼层数,请求方向> ,<请求目的楼层>,<请求楼层数,请求方向>与内部请求我按照顺序添加到一个新的数列当中,<请求目的楼层>单独添加到一个数列当中,在遍历完所有请求后将<请求目的楼层>的链表添加到队尾,这样就将请求转换成原先格式了.

类设计:

我将电梯类划分为了四个类请求类 队列类 电梯类 控制类

控制类:控制电梯的运行逻辑,根据内部请求和外部请求的情况决定电梯的移动方向和目标楼层,并处理请求的优先级。
队列类:用于存储和管理电梯的内部请求和外部请求,提供添加请求和获取请求列表的方法。
电梯类:负责模拟电梯的移动过程和输出电梯的状态信息,如当前楼层和运行方向。
乘客类 类:聚焦于乘客请求的全流程处理,负责接收原始输入,分离外部与内部请求,对请求格式进行合法性校验,提取楼层信息,转换请求格式,同时承担删除重复请求的职责

1).类图分析

解释:

Control 类:负责电梯运行控制逻辑。持有 Lift 类实例和 Queue 类实例 。通过构造函数传入楼层范围及请求队列等参数,包含一系列方法如 process 处理电梯运行流程、compareFloors 比较楼层等,用于处理电梯运行方向、请求调度等复杂逻辑。
Lift 类:表示电梯实体。有楼层范围属性、当前楼层、运行方向等属性。通过构造函数设置楼层范围,具备 moveToFloor 移动到目标楼层、getCurrentFloor 获取当前楼层等方法,用于控制电梯的实际运行动作。
Queue 类:用于管理请求队列。包含内部请求列表和外部请求列表 。有构造函数初始化队列,以及 addRequest 添加请求、getInternalRequest 获取内部请求、getExternalRequest 获取外部请求等方法,负责对电梯的各种请求进行存储和管理。
Pessager 类:聚焦于乘客请求的全流程处理,负责接收原始输入,分离外部与内部请求,对请求格式进行合法性校验,提取楼层信息,转换请求格式。

Main 类:程序入口类。包含 main 方法,作为程序启动的起点,协调其他类的初始化和运行,负责请求输入。

2).SourceMontor的生成报表

根据 SonarQube 的代码检测

(1)代码规模
总行数:代码文件总行数为 272 行,属于中等规模。这样的规模意味着代码涵盖了一定量的功能实现,但尚未达到难以管理的程度。
语句数:包含 172 个语句,代码密度适中,表明代码并非过度冗长或精简,在逻辑表达和代码量之间取得了一定平衡。
(2)代码复杂性
最大复杂度:InputHandler.parseInput() 方法的复杂度达到 8,处于可接受范围的上限。该方法承担着判断请求是否合理的重要任务,需要处理多种不同类型的输入情况和规则校验,因此产生了较高的复杂度。
平均复杂度:平均复杂度为 1.37 ,说明整体代码的复杂性相对较低。较低的平均复杂度有助于提高代码的执行效率,也使得代码在理解和维护上相对轻松,从这方面来看,代码质量较为良好。
最复杂方法:InputHandler.parseInput() 方法以 8 的复杂度成为最复杂方法,其复杂性主要源于输入请求判断逻辑的多样性。
(3)代码结构
最大嵌套深度:最大嵌套深度达到 9+ 层,出现在第 266 行。相较于之前有所提高,这是在修改代码过程中未充分留意导致的。过深的嵌套会使代码逻辑变得晦涩,增加理解和调试的难度。
平均嵌套深度:平均嵌套深度为 3.82 ,表明部分代码块存在较深的嵌套情况。虽然平均水平尚可,但仍有优化空间,以进一步提升代码的可读性和可维护性。
方法分布:每个类平均拥有 5.83 个方法,每个方法平均包含 3.54 条语句。与前两个版本的代码相比,在方法数量和语句数量的控制上表现更优,这是对前期代码进行优化的成果,使得类的职责划分更加合理,方法功能更加单一。
(4)代码注释
注释行百分比:注释行百分比为 17.0% 。在完成 PTA 作业时,对代码注释的重视程度不足,导致注释占比较低。缺乏足够的注释会使代码的可读性大打折扣,尤其在后期维护或其他开发人员接手代码时,难以快速理解代码的逻辑和意图。
(5)分支和方法调用
分支语句占比:分支语句占比极低,仅为 7% ,这表明代码的控制流较为简单,逻辑走向相对清晰,在一定程度上降低了代码的复杂性和出错概率。
方法调用数:方法调用语句数为 93 次,相较于 172 条总语句数,调用占比高达 54% 。较高的方法调用占比说明代码在组织上倾向于将功能拆分到不同方法中实现,这有助于提高代码的模块化程度和可复用性,但也需要关注方法之间的调用关系是否合理,避免过度复杂的调用链影响代码的执行效率和可维护性。

总结:

第三次修改起来还行,但对于pta上的第一个测试我一直过不了测试结果并不正确,我原本只想将不正确代码放进去保存一下,结果却真确了,我一下懵了,问了助教才知道原来检测点的逻辑可能不一样,不管怎样总算是过了我也松了口气。

三.踩坑心得

在第一次作业中由于开始时我没有规划好方法设计以及对电梯运行的理解不完全,以及对注释的不重视,我前前后后重写了三次,耗费了大量的时间,这提醒我在着手编写代码前,要投入充足时间进行全面规划。详细梳理业务逻辑,明确各个功能模块的职责与边界,合理设计方法结构。比如针对电梯运行程序,应提前规划好电梯状态管理、请求处理、运行逻辑等不同功能对应的方法,避免在开发过程中因结构混乱而频繁返工。要深入理解业务逻辑。像电梯运行规则,需清楚楼层范围、请求处理顺序、运行方向切换等细节。

我完成后的代码结果是正确的但一直是超时,为了解决这个问题我将将一些不必要的代码省去并将一些重复的方法整合起来例如原先电梯的移动为

` private void moveToFloor(int target) {

while (current != target) {
    int step = current < target ? 1 : -1;
    current += step;
    String dir = step == 1 ? "UP" : "DOWN";
    printfinfo(3, current, dir);
}

printfinfo(4, current, "");

}`

使用递归实现电梯移动到目标楼层,每次移动一层后递归调用自身,在处理相同楼层情况时不够直接

` private void moveToFloor(int target) {

    if(current==target){
        printfinfo(4,current,"");
        return;
    }
    int step;
    if(current<target){
        step=1;
    }
    else {
        step=-1;
    }
    String dir;
    if(step==1){
        dir="UP";
    }
    else{
        dir="DOWN";
    }
    current+=step;
    printfinfo(3,current,dir);
    moveToFloor(target);
}`

第二段代码采用更直接的条件判断和赋值,先判断是否到达目标楼层,然后根据当前楼层和目标楼层关系确定移动方向和步长,逻辑更清晰,避免了递归带来的额外性能开销 。
第二次作业里要提前规划好类的设计不然会像无头苍蝇一样不知道该如何划分,这类任务至关重要。如果没有合理规划类的设计,在开发过程中很容易陷入混乱,不知道如何将功能和逻辑合理地分配到不同的类中在后续的编程任务中,一定要重视前期的类设计规划工作,多思考、多分析,制定出合理的类结构,避免出现盲目开发的情况,从而提高开发效率和代码质量
第三次
第三次作业第一大问题还是运行原理问题,对于一些电梯运行原理理解错误,如:
1
20
<5,4>
<5>
<7>
end
我一直以为电梯外部请求列和内部请求列第一个只要相同就会只开一次门,认为开门情况是5->7->4,但询问老师后才知道是否只开一次门看要看运行方向,当在1楼时电梯方向UP,而<5,4>方向DOWN,固电梯先完成<5>请求,方向UP,再完成<7>请求,最后才完成<5,4>请求。

与正确的结果相比缺少了在下降过程中五楼的请求处理,但题目里却判了正确

四、改进建议

在以后的代码中还是需要添加一些注释,如果遇到很复杂的问题,经过几天后可能会忘记自己写了什么。
提高单一职责原则能力,多分一些方法,实现职责单一。
减少嵌套,嵌套过深代码的可读性和维护性都会降低,如果要修改一处,很多地方都需要修改,可能会出现遗漏错误,最终导致代码错误。
多加学习语法,在编程的过程中遇到很多不会的知识点都需要到各处查找资料,有时只能用暴力的方法,这样效率又会大大降低。

五.总结

通过三次题目集的实践,我系统掌握了面向对象编程中类的设计与实现。从电梯调度程序的迭代优化,到蒙特卡罗方法求解圆周率及其拓展应用,学会了将复杂业务逻辑拆解为不同类的职责,如电梯类、乘客类、控制类等,深刻理解了单一职责原则对代码结构的优化作用。同时,在处理输入校验、数据存储(如队列类管理请求)和算法实现过程中,对 Java 语言的语法特性、集合框架运用更加熟练。通过三周的努力,在这个大作业上花了很长时间,也基本完成pta的要求,其中深刻的理解到了类的设计的好处,比如第二次到第三次迭代时,我只需要将主函数输入进行修改,请求类做一些小改,最后在控制类中增加一些新方法完成新算法,改进的地方并不多。但第一次到第二次迭代时就要基本重新设计了。一个将类的职责划分单一的代码,对于后续改进有很大好处,我有很明显的体会。

posted @ 2025-04-19 15:26  无法表露  阅读(68)  评论(0)    收藏  举报