第一次BLOG作业
一、前言
三次PTA作业中都以电梯程序作为压轴题,可见这次大作业中电梯程序的重要性。第一次看到电梯的题目时,会因为觉得太难而不想动脑动手去敲代码,克服心理障碍后着手做会慢慢有自己提升的满足感,这或许正是此次电梯题目的意义。电梯程序的难度主要集中在算法这方面,当第一次的电梯题目做出来后,后面两次的题目也就更加轻松,除了电梯题目外的其他编程题与上学期c语言中题目类似,大部分只是由c到java的语法转变,下面的分析不作讨论。第二次、第三次的电梯题目则在原有基础上将代码分类,并遵循单一职责原则,并将代码进一步优化,在未来的学习中,学会如何划分类也是非常重要的。
二、设计与分析
第一次电梯题目分析
题目:设计一个电梯类,具体包含电梯的最大楼层数、最小楼层数(默认为1层)当前楼层、运行方向、运行状态,以及电梯内部乘客的请求队列和电梯外部楼层乘客的请求队列,其中,电梯外部请求队列需要区分上行和下行。
电梯运行规则如下:电梯默认停留在1层,状态为静止,当有乘客对电梯发起请求时(各楼层电梯外部乘客按下上行或者下行按钮或者电梯内部乘客按下想要到达的楼层数字按钮),电梯开始移动,当电梯向某个方向移动时,优先处理同方向的请求,当同方向的请求均被处理完毕然后再处理相反方向的请求。电梯运行过程中的状态包括停止、移动中、开门、关门等状态。当电梯停止时,如果有新的请求,就根据请求的方向或位置决定移动方向。电梯在运行到某一楼层时,检查当前是否有请求(访问电梯内请求队列和电梯外请求队列),然后据此决定移动方向。每次移动一个楼层,检查是否有需要停靠的请求,如果有,则开门,处理该楼层的请求,然后关门继续移动。
使用键盘模拟输入乘客的请求,此时要注意处理无效请求情况,例如无效楼层请求,比如超过大楼的最高或最低楼层。还需要考虑电梯的空闲状态,当没有请求时,电梯停留在当前楼层。
请编写一个Java程序,设计一个电梯类,包含状态管理、请求队列管理以及调度算法,并使用一些测试用例,模拟不同的请求顺序,观察电梯的行为是否符合预期,比如是否优先处理同方向的请求,是否在移动过程中处理顺路的请求等。为了降低编程难度,不考虑同时有多个乘客请求同时发生的情况,即采用串行处理乘客的请求方式(电梯只按照规则响应请求队列中当前的乘客请求,响应结束后再响应下一个请求),具体运行规则详见输入输出样例。
题目分析
设计一个电梯类,并将其输入请求分为内部请求和外部请求,同时方向优先,从此方向设计算法。
类图

Source Monitor分析

分析与心得
由上图可知,Avg Method指数和Complexity指数较高,最大复杂度为13,且代码中无注释,代码复杂度高,其中checkStop()方法复杂度高达13,由于方法内嵌套了多层循环和条件判断,在后续优化代码过程中可以合并较多的重复调用,提取子方法分解复杂逻辑,并添加必要的注释,提高代码的可读性和方便修改。
第二次电梯题目分析
题目:对之前电梯调度程序进行迭代性设计,目的为解决电梯类职责过多的问题,类设计要求遵循单一职责原则(SRP),要求必须包含但不限于设计电梯类、乘客请求类、队列类以及控制类,具体设计可参考如下类图。
电梯运行规则与前阶段单类设计相同,但要处理如下情况:
乘客请求楼层数有误,具体为高于最高楼层数或低于最低楼层数,处理方法:程序自动忽略此类输入,继续执行
乘客请求不合理,具体为输入时出现连续的相同请求,例如<3><3><3>或者<5,DOWN><5,DOWN>,处理方法:程序自动忽略相同的多余输入,继续执行,例如<3><3><3>过滤为<3>
题目分析
在第一次电梯题目的代码基础下将其划分为多个类,并遵循单一职责原则
类图

Source Monitor分析

分析与心得
代码分析
1. 代码行数与职责拆分
新增Controller类和 RequestQueue类,在参考类图设计后,通过职责拆分,代码结构得到了一定程度的优化,不同功能被分配到不同类中,使得各部分功能更加集中和明确。
2. 注释情况
注释量从 0.5 提升到 1.6,但提升幅度较小。尽管重新设计类后代码行数增多,逻辑部分也增加了注释,但仍有待后续提高。这说明在代码注释方面仍需加强,尤其是对于复杂逻辑部分,充足的注释能够帮助他人快速理解并上手代码,提高代码可读性。
3. 函数复杂度
平均复杂度:从 5.19 下降到 1.57,降至规范范围外。主要原因是在每个类中设置了一些未被使用的属性的getter和setter方法,这些简单方法拉低了整体平均复杂度。虽然平均复杂度降低看似代码更简单,但这种降低并非源于核心逻辑的优化,反而掩盖了部分复杂方法的问题。
最大复杂度:变化不大。看图后发现main方法和控制类中运行请求的方法复杂度较高。这表明在这些关键方法中,可能仍存在较为复杂的逻辑,如大量的条件判断、循环嵌套等,需要进一步优化。尽管整体平均复杂度下降,但最大复杂度未得到有效控制,说明代码中仍存在难以理解的部分。
心得
此次代码在结构设计上有改进,通过职责拆分优化了代码组织。但在注释量和函数复杂度控制方面仍有待提高。后续需对这方面进一步精进。同时,要进一步分析和优化高复杂度方法,真正提升代码质量。
第三次电梯题目分析
题目:对之前电梯调度程序再次进行迭代性设计,加入乘客类(Passenger),取消乘客请求类,类设计要求遵循单一职责原则(SRP),要求必须包含但不限于设计电梯类、乘客类、队列类以及控制类,具体设计可参考如下类图。
电梯运行规则与前阶段相同,但有如下变动情况:
乘客请求输入变动情况:外部请求由之前的<请求楼层数,请求方向>修改为<请求源楼层,请求目的楼层>
对于外部请求,当电梯处理该请求之后(该请求出队),要将<请求源楼层,请求目的楼层>中的请求目的楼层加入到请求内部队列(加到队尾)
题目分析
仍需遵循单一职责原则,在前一次代码的基础上迭代,并且输入格式变化,要调整输入时的正则表达式的匹配形式,并通过外部请求的两个楼层判断请求方向,进而对电梯的调度做出正确的判断
类图:

Source Monitor分析:

分析与心得
代码分析
1. 代码行数与结构变化
相较于之前有了一定程度的调整。新增了Controller类和RequestQueue类,实现了职责拆分,符合高耦合性低设计理念,使得代码结构在功能划分上更加清晰,不同类专注于特定职责,提高了代码的可维护性与可读性。
2. 注释情况
注释行占比仅 2.3% ,提升幅度极小。尽管代码行数有所变化且进行了类的重新设计,但注释量依旧远未达到java规范要求。这会导致在复杂逻辑理解上有较大阻碍,其他人难以快速把握代码意图,尤其是在处理和修改 ElevatorController.processInput()这类复杂方法时,缺乏注释会大幅增加理解的时间成本。
3. 函数复杂度
平均复杂度:平均复杂度处于相对较低水平,但结合最大复杂度为10来看,平均复杂度低可能并非源于整体代码逻辑的简洁,可能由于存在大部分简单重复的方法,如getter、setter方法。
最大复杂度:最大复杂度为 10 ,集中在ElevatorController.processInput()方法,说明该方法存在复杂的逻辑,如多层嵌套的条件判断。尽管平均复杂度低于规范值,但高复杂度方法会成为代码扩展的瓶颈。
总结与心得
此次代码在结构设计上通过职责拆分有一定优化成果,然而在注释和函数复杂度方面仍有欠缺。后续要慢慢培养添加注释的习惯,特别是对像ElevatorController.processInput()这样的高复杂度方法进行详尽注释。同时,不能仅关注平均复杂度指标,要深入剖析高复杂度方法,通过优化算法、减少不必要的嵌套等手段,真正降低代码的复杂性,提升代码质量,使其在符合规范的同时更易于理解。
三、踩坑心得
踩坑:
1、未对题目提前进行必要的需求和类的分析,直接看到电梯题目后开始在电脑里敲代码,脑子里一团乱麻,敲完一些基本的代码后,不知从何下笔,后面慢慢导致自己内心的恐惧与慌张,从而对题目产生排斥,而且后续写出的代码在调试与运行时经常报错,代码里冗余和重复的内容偏多,缺乏简洁性,后续里如果要添加一些变量或者其他,显得特别麻烦
2、代码里注释量的确非常少,之后写的代码在隔过两个星期后去看,仍需花费一些时间去理解其中的逻辑关系
3、由于一开始不知道电梯运行的具体算法和老师所说的分为内部请求队列和外部请求队列的意思,在写代码时绕了很多弯路,后来老师发布了较为详细的示意图告知我们此次电梯题目的算法框架,才从中理解了具体意思
四、改进建议
1、在以后的迭代量高的题目里做到遵循单一职责原则,尽量降低各个类之间的耦合度,这样修改代码的错误时能节约很多时间
2、培养自己写代码时添加注释的习惯,一个项目里并非只有一个人完成任务,注释便于团队成员间的配合和理解,对一个项目的研发有莫大的好处
3、多在课外培养自己的算法思维能力,并在网上多去了解学习其他的算法
4、培养自己的团队协作能力,如果一个人单打独干,是不能解决得了问题的,这次电梯的题目使我意识到团队间交流协作的重要性
五、总结
经过这三次电梯题目的锻炼,提升我对迭代量高的题目的理解和逻辑思维能力,更加清晰地了解面向对象编程的过程,在此过程中我学习到了如何使用Source Monitor来检测代码的复杂度和注释情况,更加熟悉了如何用PowerDesigner画类图和类与类之间的关系,如何在博客里查询信息,与其他编程人员交流各自的见解,并发表自己的学习成果,这次的blog作业令我收获颇丰,希望我在之后的大作业和blog作业中学习到更多知识,并提高自身的编程基础能力。
浙公网安备 33010602011771号