zz-0807ok

  博客园  :: 首页  :: 新随笔  :: 联系 :: 订阅 订阅  :: 管理
  1. 前言
    首先说明一下这次大作业的情况,第一次作业得分情况是100分,第二次作业的得分情况是75分,第三次作业的得分情况是100分。完成情况很不尽人意,第一次作业的测试点较为简单和第二题的一个测试点没过,导致失分25分,第三次作业在第二次作业的代码上全面完善代码终于在结束前的三天完成。

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

    代码总行数:157行,代码行数较小,表明代码难度不大。

    语句:104行,代码适中。

    分支语句百分比:23.1%,比例较低,表明分支逻辑不多,代码复杂性不大。

    方法调用语句:52个,这个值相对较低,说明代码代码调用不频繁,读起来更容易理解。

    代码注释百分比:0%,由于本人最后将代码注释全删了,使代码注释为0。

    类和接口:2个,分别使电梯类和测试类。

    每个类的方法数:6.5个,这个数据并不大,代码所调用的方法并不多,可能造成代码的复用性较低。

    每个方法中的代码行数:6.23行,代码行数较少,说明这道题目并不是很难,较为简单。

    最复杂的方法:ElevatorSystem.shouldPrioritizeInternal(),56行,说明这段代码行数较大,较为复杂,可能没做到单一性原则,使这个方法较为复杂。

    最大复杂度:9,这是一个比较危险的值,一般公司的复杂度不会超过10,而9这个值比较危险,这意味着,该方法可能逻辑比较复杂,有必要进行重构降低复杂度。

    最大代码深度:5,这是一个较高的值,表明代码中存在较深的嵌套,可能造成代码难以理解,增加代码维护的难度。

    平均代码深度:2.4,相对较高,表明代码中有一定程度的嵌套,整体上还可控。

    平均复杂度:3.31,这个值相对较高,可能使部分方法的复杂度提升,造成部分代码难以理解,可读性较低。
    (3)总体分析:

    1. 代码结构​​
      ​​ 模块划分​​:
      分为Main(输入处理)和ElevatorSystem(核心逻辑)两类,符合单一职责原则。ElevatorSystem封装电梯状态、请求队列及移动逻辑,模块化程度较高。

​​ 方法设计​​:
关键方法如shouldPrioritizeInternal(优先级判断)和simulateOperation(调度模拟)实现核心逻辑,但存在以下问题:

​​ 复杂度超标​​:
shouldPrioritizeInternal嵌套条件过多,圈复杂度达9,违反单一职责原则。

​​ 重复逻辑​​:
parseFloor与parseDirection多次解析字符串,未封装为工具方法。
​​ 2. 逻辑缺陷​​。
​​ 请求处理漏洞​​:
同一楼层的多个请求仅处理一次(如if (parseFloor(nextInternal) == targetFloor)),未考虑同层多请求场景。方向切换逻辑(determineNewDirection)未处理无请求时的默认行为,可能导致空指针异常。

​​ 效率问题​​:
电梯逐层移动模拟(moveToTarget循环)未优化路径,实际场景应直接跳转目标楼层。

​​ 3. 可维护性风险​​
​​ 零注释​​:
核心算法(如优先级规则)无注释,增加理解成本。

​​ 硬编码方向​​:
使用字符串"UP"/"DOWN"而非枚举,易因拼写错误引发逻辑错误。

​​ 紧耦合设计​​:
内外请求队列(internalRequests/externalRequests)直接依赖ArrayList,扩展性受限。

​​ 4. 改进建议​​
​​ 降低复杂度​​:拆分shouldPrioritizeInternal为方向策略类,采用状态模式优化条件分支。
​ ​增强健壮性​​:添加输入校验、异常处理及空请求检查。
​​ 优化性能​​:使用优先级队列按楼层排序请求,减少无效移动。
​​ 代码规范​​:引入枚举类型、Javadoc注释及单元测试覆盖核心逻辑。
​​ (4)总结​​:
当前代码实现了基础电梯调度功能,但存在逻辑漏洞与维护性缺陷。需通过重构
复杂方法、优化数据结构和补充校验机制提升代码质量,方可在实际场景中可靠
运行。
2.第二次作业分析
(1).题目:
对之前电梯调度程序进行迭代性设计,目的为解决电梯类职责过多的问题,类设计要求遵循单一职责原则(SRP),要求必须包含但不限于设计电梯类、乘客请求类、队列类以及控制类,具体设计可参考如下类图。
电梯迭代1类图.png
电梯运行规则与前阶段单类设计相同,但要处理如下情况:

乘客请求楼层数有误,具体为高于最高楼层数或低于最低楼层数,处理方法:程序自动忽略此类输入,继续执行
乘客请求不合理,具体为输入时出现连续的相同请求,例如<3><3><3>或者<5,DOWN><5,DOWN>,处理方法:程序自动忽略相同的多余输入,继续执行,例如<3><3><3>过滤为<3>
注意:本次作业类设计必须符合如上要求(包含但不限于乘客请求类、电梯类、请求队列类及控制类,其中控制类专门负责电梯调度过程),凡是不符合类设计要求此题不得分,另外,PTA得分代码界定为第一次提交的最高分代码(因此千万不要把第一次电梯程序提交到本次题目中测试)。

(2).代码分析:

 代码总行数:225行,代码行数较第一次作业有所提升,但依旧表明代码难度不大。

 语句:142行,代码适中。

 分支语句百分比:20.4%,比例较低,和第一作业相差不大,表明分支逻辑不多,代码复杂性不大。

 方法调用语句:63个,这个值相对较低,说明代码代码调用不频繁,读起来更容易理解。

 代码注释百分比:0%,由于本人最后将代码注释全删了,使代码注释为0。

 类和接口:6个,分别使电梯类和测试类,外部请求类,控制系统类,电梯请求类,方向枚举类。

 每个类的方法数:4.5个,较上次代码有所下降,代码所调用的方法并不多,可能造成代码的复用性较低。

 每个方法中的平均代码行数:3.56行,代码行数较少,说明这道题目并不是很难,较为简单。

 最复杂的方法:Main(),8行,说明这段代码行数较小,因为这段代码到最后都没写出,所以存在一定的错误,下次需要改正。

 最大复杂度:9,这是一个比较危险的值,一般公司的复杂度不会超过10,而9这个值比较危险,这意味着,该方法可能逻辑比较复杂,有必要进行重构降低复杂度。

 最大代码深度:5,这是一个较高的值,表明代码中存在较深的嵌套,可能造成代码难以理解,增加代码维护的难度。

 平均代码深度:2.01,相对较高,表明代码中有一定程度的嵌套,整体上还可控。

 平均复杂度:2.52,这个值相对上次作业有明显下降代码的可读性提升,代码难度下降,理解较为简单。

(3).总体分析:
1. 结构优化​​
​​ 职责分离​​:
新增 NewController(控制逻辑)、NewRequestQueue(请求管理)、NewElevator(电梯状态)等类,​​职责划分清晰​​,解决了旧版代码的紧耦合问题。

​​ 枚举替代字符串​​:
使用 Direction 枚举管理方向,​​避免硬编码风险​​,提升类型安全性。

​​ 请求对象封装​​:
NewExternalRequest 封装外部请求的楼层和方向,​​增强数据抽象能力​​。

​​ 2. 逻辑改进​​
​​ 请求去重​​:
NewRequestQueue 的 addInternal/addExternal 方法避免重复添加相同请求,​​减少冗余处理​​。

​​ 方向更新策略​​:
updateDirectionAfterInternal 调整电梯方向​​,逻辑更健壮。

​​ 3. 现存问题​​
​​高复杂度方法​​:
shouldPrioritizeInternal 嵌套条件仍导致​​圈复杂度达9​​,需拆分为策略类。

​​ 路径效率低下​​:
moveTo 逐层移动电梯(elevator.current +=1),​​未优化跨楼层跳跃​​,性能待提升。

​ ​扩展性限制​​:
未定义接口(如 IElevator),​​无法支持多电梯类型​​,依赖具体实现。

​​ 文档缺失​​:
关键算法无注释,​​维护成本较高​​。

​​ 4. 改进建议​​
​​ 策略模式​​:将优先级逻辑拆分为 PriorityStrategy 接口及其实现类。

     ​​单元测试​​:针对复杂方法补充测试用例,覆盖边界条件。

​​ (4).总结​​
当前代码通过模块化设计解决了旧版架构缺陷,但核心算法复杂度和扩展性仍需
优化。建议进一步重构高复杂度方法并引入接口抽象,以构建高可维护的电梯调
度系统。
3.第三次作业分析:
(1)题目:
对之前电梯调度程序再次进行迭代性设计,加入乘客类(Passenger),取消乘客请求类,类设计要求遵循单一职责原则(SRP),要求必须包含但不限于设计电梯类、乘客类、队列类以及控制类,具体设计可参考如下类图。
类图.png
电梯运行规则与前阶段相同,但有如下变动情况:

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

 代码总行数:310行,代码行数较第一次和第二次作业有明显提升,表明代码难度大大提高。

 语句:198行,将近三分之二的代码都为语句,表明代码还是比较多。

 分支语句百分比:26.8%,与前两次相比有所提升,但仍表明分支逻辑不多,代码复杂性不大。

 方法调用语句:119个,这个值相对较大,说明代码代码调用较频繁,这可能影响代码之间的耦合性和性能。

 代码注释百分比:0.6%,和前两次相比代码行数有所提升,写出注释可以增加代码的可读性。

 类和接口:6个,分别使电梯类和测试类,乘客类,控制系统类,电梯请求类,方向枚举类。

 每个类的方法数:4.5个,和第二次代码相同,代码所调用的方法并不多,可能造成代码的复用性较低。

 每个方法中的平均代码行数:5.56行,代码行数提高,说明难度提高,方法的复杂性提高。

 最复杂的方法:NewController.derminDirection(),46行,该方法行数较多,内部比较复杂,和前两次相比有明显提升,并且内部分支比较多,情况比较复杂,应该提高代码的简略性,使用更为简便的方法。

 最大复杂度:27,这是一个很危险的值,一般公司的复杂度不会超过10,而27这个值比较危险,这意味着,该方法逻辑比较复杂,可以在将该方法进行分解,分解成多个方法,减少复杂度。

 最大代码深度:5,这是一个较高的值,表明代码中存在较深的嵌套,可能造成代码难以理解,增加代码维护的难度。

 平均代码深度:2.66,相对较高,表明代码中有一定程度的嵌套,整体上还可控。

 平均复杂度:3.89,这个值相对较小,但和前两次相比有明显提升,也就说明代码的难度大大提升。

(3)总体分析:
​1. 代码结构与设计改进​​
本次代码在模块化设计上进行了显著优化,但核心逻辑复杂度与功能实现仍存在明显缺陷:

      ​​新增类与职责划分​​:
        ​​Passenger 类​​:封装乘客请求的​​源楼层​​、​​目标楼层​​和​​方向​​,明确外部请求的完整生命周期。
        ​​NewRequestQueue 类​​:分离内部请求(目标楼层)与外部请求(Passenger对象),但队列管理逻辑混乱(如addInternal和addInternalRequest重复定义)。

​​ NewController 类​​:整合方向决策(determinDirection)与请求处理(processRequests),但方法间耦合度过高。

     ​​方向决策优化​​:
        determinDirection 方法尝试根据当前请求动态调整方向,但嵌套条件分支过多(​​圈复杂度超过15​​),导致逻辑可读性差且易出错。
  ​​2. 核心逻辑缺陷​​

​​ 请求处理漏洞​​:
​​ 外部请求解析错误​​:

​​ 楼层越界风险​​:
up()和down()方法仅检查current与min/max的关系,但未处理连续移动时的越界(如current=max时调用up()仍可能执行current++)。

     ​​队列管理问题​​:

​​ 重复添加请求​​:addExternal方法未去重相同源楼层但不同目标楼层的请求,导致队列冗余。
​​3. 功能实现问题​​
​​电梯移动逻辑错误​​:
​​无效停靠​​:shouldStop方法在电梯到达外部请求的源楼层时开门,但未验证该请求方向是否与电梯当前方向一致(如电梯下行时响应UP方向的外部请求)。

     ​​方向更新策略矛盾​​:
     在processRequests中,若内部请求队列为空,电梯无法正确处理外部请求的目标楼层(如外部请求的destinationfloor未加入内部队列)。
     determinDirection中未处理无请求时的默认行为,电梯可能停止运行。
  ​​4. 代码可维护性隐患​​

​​ 命名与注释问题​​:
方法名拼写错误(如determinDirection应为determineDirection)。
零注释:关键算法(如shouldStop的条件优先级)无解释,维护成本高。
​​冗余代码​​:
NewRequestQueue类包含冗余方法(addInternal与addInternalRequest功能重复)。
Passenger.getDirection()重复计算方向,应改为在构造函数中初始化。
​​ 5. 改进建议​​:
​​性能优化​​:
将LinkedList替换为PriorityQueue,按楼层排序请求,减少无效移动。
​​健壮性增强​​:
在NewElevator中添加moveTo方法,直接跳转目标楼层并记录路径。增加电梯状态机(如IDLE, MOVING),避免无效方向切换。
(4)总结:
当前代码通过引入Passenger类明确了请求生命周期,但核心逻辑存在严重漏洞(如方向冲突、解析错误),且可维护性差。建议优先修复输入解析与方向决策逻辑,再通过设计模式解耦模块依赖,最终构建高可靠的电梯调度系统。
5.总体总结:
面向过程与面向对象的比较
面向过程是一种以过程为中心的编程思想,而面对对象是一门以对象为基本程序结构单位的程序设计语言。面向过程只需要分析解决问题所需要的步骤,然后用模块化的函数把这些步骤一步步的实现,使用的时候一个
个调用这些函数就可以了,而面对对象以 对象为主体,对象具有静态类型和多个可能的动态类型,在基本层次关系中的不同类中共享数据操作。

面向对象设计的基本原则理解
   目前只在网上了解了五大基本原则:模块化,抽象,信息隐藏,低耦合,高内聚。

测试对于编码质量的重要性
   如果没有详细的测试,那么代码可能有潜在的很多问题,所以代码必须要经过反复,多样的测试,才能保证代码的精确性,简便性,由此可见测试的重要性。

假如让你设计测试用例,你会如何做?
   我会将每个测试点细化并且加上详细的测试点说明,方便程序的调试。

课程收获
   学会了一些关于Java的语法和知识,但最重要的是了解了一种面对对象的编程思想,它可以让代码更简洁,程序逻辑更简单。

对课程的建议
   老师讲课非常好,也非常的认真负责,每次有作业或者重要的通知都会多次提醒同学,而且解答学生的问题很有耐心。但是希望能增加一些PTA的题量,降低一些难度,并且在题目后面有详细的测试点。     
posted on 2025-04-19 13:19  卡位  阅读(69)  评论(0)    收藏  举报