第一次Blog作业

一、 前言
在第五,六,七次题目集中,共有5+3+3道题目,题量不算大,但难度不小,其中每个题目集分别都有一题难度较大的电梯及几道难度适中的编程题,题目集五主要针对正则表达式进行出题,并且每题只需创建一个类,题目集六和七则围绕类的设计进行出题,需理清各个类之间的关系,随后设计各个类,并且各个类之间有不同的关系,需要对其进行分析并作答。对于最难的题目——电梯,则都具有很高的难度及复杂度,在电梯题目中,需要设计多个类与对象,将各个属性封装至类中,通过创建对象来模仿电梯运行,通过各种方法实现电梯的处理请求,楼层移动,开关门等行为,通过队列来按顺序处理内部和外部请求,使用ArrayList来储存请求。后两次题目集的电梯题则具有更高的难度,在各个方面的难度都有所提高。处理请求的逻辑要求更加清晰,且要熟练运用队列中元素的添加,删除和遍历。要确保是先进先出。经过这些时间的学习,我逐渐了解了面向对象程序设计,让我意识到面向对象与面向过程的区别,也意识到面向对象程序设计并非一门简单的学科,每次题目集的发出都可以让我意识到自己的不足之处,推动自己去学习,接下来我将对我所遇到的问题进行总结。
二、 设计与分析
题目集五:
题目要求:
设计一个电梯类,具体包含电梯的最大楼层数、最小楼层数(默认为1层)当前楼层、运行方向、运行状态,以及电梯内部乘客的请求队列和电梯外部楼层乘客的请求队列,其中,电梯外部请求队列需要区分上行和下行。
电梯运行规则如下:电梯默认停留在1层,状态为静止,当有乘客对电梯发起请求时(各楼层电梯外部乘客按下上行或者下行按钮或者电梯内部乘客按下想要到达的楼层数字按钮),电梯开始移动,当电梯向某个方向移动时,优先处理同方向的请求,当同方向的请求均被处理完毕然后再处理相反方向的请求。电梯运行过程中的状态包括停止、移动中、开门、关门等状态。当电梯停止时,如果有新的请求,就根据请求的方向或位置决定移动方向。电梯在运行到某一楼层时,检查当前是否有请求(访问电梯内请求队列和电梯外请求队列),然后据此决定移动方向。每次移动一个楼层,检查是否有需要停靠的请求,如果有,则开门,处理该楼层的请求,然后关门继续移动。
使用键盘模拟输入乘客的请求,此时要注意处理无效请求情况,例如无效楼层请求,比如超过大楼的最高或最低楼层。还需要考虑电梯的空闲状态,当没有请求时,电梯停留在当前楼层。
请编写一个Java程序,设计一个电梯类,包含状态管理、请求队列管理以及调度算法,并使用一些测试用例,模拟不同的请求顺序,观察电梯的行为是否符合预期,比如是否优先处理同方向的请求,是否在移动过程中处理顺路的请求等。为了降低编程难度,不考虑同时有多个乘客请求同时发生的情况,即采用串行处理乘客的请求方式(电梯只按照规则响应请求队列中当前的乘客请求,响应结束后再响应下一个请求),具体运行规则详见输入输出样例。

整体设计思路:
电梯题的核心是模拟单部电梯的调度过程,要依据乘客的请求,按照特定规则调度电梯运行。设计时应遵循面向对象编程思想,将不同功能封装到不同类中,提升代码的可维护性与可扩展性。主要涉及电梯类、请求类,同时要处理好输入输出以及请求的调度逻辑。
各部分详细设计:
对于题目集五的电梯题,共设计三个类:Elevator(电梯类),Request(请求类),Main(主类)。

  1. Elevator(电梯类):
    属性设计:
    minFloor:电梯可到达的最小楼层
    maxFloor:电梯可到达的最大楼层
    currentFloor:电梯当前所在的楼层
    direction:电梯的运行方向
    state:电梯的运行状态
    internalRequests:电梯内部的请求队列
    externalUpRequests:电梯外部的上行请求队列
    externalDownRequest:电梯外部的下行请求队列

方法设计:
构造方法:空参构造和全参构造
各属性的get,set方法
addInternalRequest(int floor):添加内部请求
addExternalRequest(int floor, String direction):添加外部请求
processRequests():处理所有请求
move():电梯运行,根据方向更新电梯所在楼层
openDoor():开门
clossDoor():关门
shouldStop():判断当前楼层是否需要停止
handleRequestsAtCurrentFloor():处理当前楼层的请求,并将该请求删除
findNextDirection():读取下一个请求来确定运行方向
isValidFloor(int floor):判断楼层是否合理

  1. Request(请求类):
    属性设计:
    floor:请求的楼层
    direction:请求的方向

方法设计:
构造方法:空参构造和全参构造
各属性的get,set方法

  1. Main(主类):
    功能:读取用户输入,解析输入并添加请求,最后处理请求。
    数据结构选择:
    对于请求的存储,使用队列的方式,符合先进先出。使用LinkedList实现队列。
    Souce Monitor分析结果:

行数(Lines):189 行,反映代码文本长度。
语句数(Statements):105 条,体现代码执行单元数量。
分支语句占比(Percent Branch Statements):26.7% ,说明代码中分支逻辑(如 if - else、switch 等)的比例。
方法调用数(Method Call Statements):57 次,反映方法间调用频繁程度。
注释行占比(Percent Lines with Comments):7.9% ,注释较少,可能影响代码可读性。
类和接口数量(Classes and Interfaces):1 个 ,结构较简单。
每个类的方法数(Methods per Class):9.00 个 ,类内方法较多。
每个方法平均语句数(Average Statements per Method):9.67 条 ,方法语句数量适中。
最复杂方法行号(Line Number of Most Complex Method):151 行,最复杂方法名(Name of Most Complex Method):Main.main() ,主方法复杂度最高。
题目集六:
题目要求:
对之前电梯调度程序进行迭代性设计,目的为解决电梯类职责过多的问题,类设计要求遵循单一职责原则(SRP),要求必须包含但不限于设计电梯类、乘客请求类、队列类以及控制类,具体设计可参考如下类图。

电梯运行规则与前阶段单类设计相同,但要处理如下情况:
• 乘客请求楼层数有误,具体为高于最高楼层数或低于最低楼层数,处理方法:程序自动忽略此类输入,继续执行
• 乘客请求不合理,具体为输入时出现连续的相同请求,例如<3><3><3>或者<5,DOWN><5,DOWN>,处理方法:程序自动忽略相同的多余输入,继续执行,例如<3><3><3>过滤为<3>

  1. Elevator(电梯类):
    属性设计:
    minFloor:电梯的最小楼层
    maxFloor:电的最大楼层
    currentFloor:电梯当前所在的楼层
    direction:电梯的运行方向
    state:电梯的运行状态
    方法设计:
    构造方法:空参构造和全参构造
    各属性的 get 方法
    move():根据电梯的运行方向更新当前楼层
    openDoor():开门
    closeDoor():关门
    shouldStop(PassengerRequest request):判断在当前楼层是否需要停止

  2. PassengerRequest(乘客请求类):
    属性设计:
    floor:请求的楼层
    direction:请求的方向
    方法设计:
    构造方法:空参构造和全参构造
    各属性的 get 方法
    isValid(int minFloor, int maxFloor):判断请求的楼层是否在电梯可运行的有效楼层范围内

  3. RequestQueue(队列类):
    属性设计:
    internalRequests:存储电梯内部乘客请求的队列
    externalUpRequests:存储电梯外部上行乘客请求的队列
    externalDownRequests:存储电梯外部下行乘客请求的队列
    方法设计:
    构造方法:初始化三个请求队列
    addInternalRequest(PassengerRequest request):向内部请求队列添加一个乘客请求
    addExternalRequest(PassengerRequest request):根据请求的方向,将请求添加到相应的外部请求队列
    getNextInternalRequest():从内部请求队列中获取下一个请求
    getNextExternalRequest():从外部请求队列中获取下一个请求
    hasInternalRequests():判断内部请求队列是否为空
    hasExternalRequests():判断外部请求队是否为空

  4. ElevatorController(控制类):
    属性设计:
    elevator:关联的电梯对象
    requestQueue:关联的请求队列对象,用于获取乘客请求
    方法设计:
    构造方法:初始化控制类时传入电梯对象和请求队列对象
    processRequests():处理所有乘客请求
    findNextDirection():根据请求队列中的下一个请求来确定电梯的运行方向

  5. Main(主类):
    功能:读取用户输入,解析输入的乘客请求,过滤掉无效请求(如楼层超出范围)和重复请求,将有效请求添加到相应的请求队列中,然后创建电梯对象、请求队列对象和控制类对象,并调用控制类的 processRequests() 方法来处理请求,模拟电梯的运行过程。
    数据结构选择
    对于请求的存储,依旧使用队列的方式,符合先进先出原则。使用 LinkedList 实现队列,分别创建内部请求队列、外部上行请求队列和外部下行请求队列,便于对不同类型的请求进行管理和操作。
    Souce Monitor分析结果:

行数(Lines):465 行,说明代码文本较长。较长的代码行数可能意味着功能复杂,维护难度也相对较高。后续可考虑按功能模块拆分代码,提升可读性和可维护性。
语句数(Statements):163 条,反映代码中执行单元数量。语句数和行数有一定差异,可能是因为存在空行、注释行等非执行语句。
分支语句占比(Percent Branch Statements):22.7% ,表示代码中分支逻辑(如 if - else、switch 等)占比不算太高,但仍有优化空间。若分支逻辑过于复杂,可通过提取方法、使用策略模式等方式简化。
方法调用语句数(Method Call Statements):92 次,方法间调用频繁,说明代码模块化程度尚可,但需关注方法调用的合理性,避免过度复杂的调用层级。
注释行占比(Percent Lines with Comments):39.6% ,注释较为丰富,有助于理解代码逻辑,对后续维护和他人阅读代码很有帮助。可继续保持良好的注释习惯,特别是在关键算法、复杂逻辑处。
类和接口数量(Classes and Interfaces):1 个 ,表明代码结构相对简单,所有功能集中在一个类中。但从大型项目开发和代码可维护性角度,可考虑进一步拆分类,遵循单一职责原则。
每个类的方法数(Methods per Class):27.00 ,方法数量较多,可能导致 Main 类职责不单一。可按功能将方法拆分到不同类中,降低类的复杂度。
每个方法平均语句数(Average Statements per Method):5.89 ,方法语句数量不算多,方法相对简洁。但结合较多的方法数,需关注方法之间的逻辑耦合度。
最复杂方法行号(Line Number of Most Complex Method):393 ,最复杂方法名(Name of Most Complex Method):Main.main() ,主方法复杂度最高。主方法承担了较多功能,如输入输出、对象创建、业务逻辑调用等。可将其中部分功能抽取到独立方法或类中,降低主方法复杂度。
三、 踩坑心得

  1. 要注意数组越界,可能导致非零返回
  2. 正则表达式很实用,我对正则表达式的使用也逐渐熟练
  3. 学会了使用LinkedList
    四、 改进建议
  4. 代码复杂度太高,不够精简
  5. 类与类之间的关系不是很清晰
  6. 增加一些代码的注释,使代码具有更好的可读性
    五、 总结
    经过这三次的题目集,我学习到许多知识,包括但不限于队列,元素的增加,删除,遍历,调试工具的使用,不同类之间的调用等,同时也发现更多不足之处,之后的时间我会更加努力去完善。
posted @ 2025-04-20 22:38  大貉妖处理专家  阅读(15)  评论(0)    收藏  举报