题目集5-7电梯题目迭代blog

一、前言
在本次三个电梯题目集中,围绕电梯调度程序开展了三次迭代开发,循序渐进地深化对面向对象编程及设计原则的掌握。第一次题目集着重基础功能实现,聚焦电梯类设计,涵盖关键属性与请求队列管理,在理解和实现电梯运行规则上有挑战,基础难度,但是为下次迭代能提供思路。第二次迭代引入单一职责原则(SRP)优化类设计,新增乘客请求类、队列类及控制类,要求增加,难度提升至需确保各类型职责明确、协同流畅并处理复杂请求情况,对代码架构和逻辑严谨性要求更高。第三次迭代延续 SRP,取消乘客请求类并引入乘客类,大幅调整输入格式及规则,虽类数量没有增加,但对类功能及交互细节要求更精细,因架构与规则变动,难度显著提升,着重考验对复杂系统的设计和逻辑的调整 。
二、设计与分析
第一次作业:
要求:
设计一个电梯类,具备最大楼层数、最小楼层数(默认 1 层)、当前楼层、运行方向、运行状态(停止、移动中、开门、关门等),以及电梯内和电梯外(区分上行和下行)的请求队列。电梯默认静止在 1 层,有请求时开始移动,优先处理同方向请求,运行中每层检查请求以决定移动方向,有停靠请求则开门处理再关门继续。
电梯实现逻辑:
内部请求为空外部不为空时,我就执行外部的;外部请求为空,内部请求不为空时,我就执行内部的;都不空时,将电梯运行分为同侧和不同侧(就是外部请求楼层和内部请求楼层跟当前电梯所在楼层相比在没在电梯同侧)。在同侧时,如果电梯外部请求离电梯更近且方向与电梯运行同方向,就先去外部请求的楼层,否则就去内部请求;如果不同侧,外部请求方向向上且内部请求楼层在外部请求上面先去外部请求,外部请求方向向下且内部请求楼层在外部请求下面先去外部请求,其余的都去外部请求。
电梯实现方法:
1. Elevator 类
属性:
maxFloor:电梯所能到达的最大楼层。
minFloor:电梯所能到达的最小楼层,默认为 1。
currentFloor:电梯当前所在的楼层。
direction:电梯的运行方向,取值为 "UP"、"DOWN" 。
runningState:电梯的运行状态。
inqueueRequests:电梯内部乘客的请求队列。
outqueueRequests:电梯外部乘客的请求队列。
number:用于输出一开始的一楼打印
方法:
Elevator(int minFloor, int maxFloor):
初始化电梯的最小楼层、最大楼层、当前楼层、运行方向、运行状态以及请求队列。
isValidFloor(int floor):
检查输入的楼层是否在电梯可到达的范围内。
addRequest(String request):
根据输入的请求格式,将请求添加到相应的请求队列中。请求格式有两种:<楼层号> 表示电梯内部请求,<楼层号,UP> 或 <楼层号,DOWN> 表示电梯外部请求。
getOutDirection(String request):
从电梯外部请求中提取运行方向("UP" 或 "DOWN")。
getFloor(String request):
从请求中提取目标楼层号。
run():
电梯的核心运行方法,不断处理请求队列中的请求。根据请求队列的情况,选择处理电梯内部请求或电梯外部请求,处理完一个请求后,更新电梯的当前楼层和请求队列。
show(int start, int end, String dir):
输出电梯的运行过程,包括每一层的当前楼层、运行方向,以及到达目标楼层后的开门和关门信息。
获取属性的方法:
提供了一系列获取电梯属性的方法,如 getMaxFloor()、getMinFloor() 等。
2. Main 类
这个类是程序的入口,负责读取用户输入并启动电梯的运行。
方法:
方法main(String[] args):
使用 Scanner 类从控制台读取用户输入的最小楼层、最大楼层和一系列请求。创建 Elevator 对象,并将用户输入的请求添加到电梯的请求队列中。调用 elevator.run() 方法启动电梯的运行。

代码规模:

类图如下:

复杂度分析:

我的Elevator1.run()复杂度高达 33,语句数 55,最大深度 7,调用次数 41 。这是我的电梯运行的核心方法,包含了电梯的调度算法、状态转换等逻辑。
Elevator1.show()复杂度 12,语句数 23,最大深度 5,调用次数 16 。用于展示电梯相关信息,如当前楼层、运行状态等。语句数和复杂度相对较高,。
Main.main()复杂度 3,语句数 12,最大深度 3,调用次数 9 。作为程序入口,但语句数较多,存在一些可以优化和简化的代码。
其余的方法复杂度大多为1,语句简单。
从雷达图上来看,在我的电梯运行方法代码中,复杂程度高,容易出现方法调用出错和承担过多功能可读性下降。
采坑心得:
在数据处理上,如果有非法字符,容易导致电梯运行报错,Elevator 类职责混杂,像 run 方法集多种功能于一身,复杂度达 33,没有实现单一职责原则。测试用例覆盖窄,一旦范围不断扩大,我的边界问题逐渐暴露,容易运行超时和越界。
改进建议:
要将 Elevator 类复杂功能拆分,如把请求调度和显示逻辑分别封装成独立类。强化输入校验,严格检查输入格式;增添注释提高代码可读性。考虑边界问题,提高代码逻辑缜密性把多种情况都考虑到。
第二次作业:
要求:
在第一个电梯要求下需遵循单一职责原则,设计包含电梯类、乘客请求类、队列类、控制类(负责电梯调度)。电梯运行规则不变,要处理乘客请求楼层数有误(高于最高或低于最低楼层,自动忽略)和请求不合理(连续相同请求,过滤多余)情况。输入格式为:先输入最小、最大楼层数,后续每行一个乘客请求(内 <楼层数>,外 < 所在楼层数,乘梯方向 > ),输入 “end”(不区分大小写)结束。
电梯运行逻辑:
内部请求为空外部不为空时,我就执行外部的;外部请求为空,内部请求不为空时,我就执行内部的;
都不为空的时候,看两个请求的队头,当内部请求和外部请求的楼层在当前的楼层同一侧就是都在上侧或者都在下侧(大条件)
如果外部楼层离当前楼层近,(小条件)
(光近还不行,内部外部的请求在当前楼层上面,且外部请求方向为上或者内部外部请求楼层在当前楼层下面,外部请求方向为下)才会先去外部请求,其他的情况都会先去内部请求的楼层。
如果内外发出请求的楼层相等(小条件)
两个都执行。
如果内部请求离当前楼层近,(小条件)
无论如何都先去内部请求楼层。
内部和外部请求不在同一侧的话(大条件)
一是在当前楼层此时电梯方向向上,外层请求在当前楼层上方,外部请求的方向是上时,去外部请求的楼层;
二是当前楼层此时电梯方向向上,外部请求在当前楼层上面,且外部请求的方向是下时,去外部请求的楼层;
三是其他的情况都是先去内部请求。
电梯实现方法:
Elevator1 类:
属性:包含 maxFloor(最大楼层)、minFloor(最小楼层)、currentFloor(当前楼层)、direction(运行方向)、runningState(运行状态)。
方法:
构造方法:接收 minFloor 和 maxFloor 作为参数,初始化电梯的基本属性,如将 currentFloor 设置为 minFloor,direction 设置为 "IDLE",runningState 设置为 "STOPPED"。
方法:提供了一系列 get 和 set 方法,用于获取和设置电梯的各个属性,方便其他类对电梯状态进行访问和修改。
RequestQueue 类:
属性:有 inqueueRequests(内部请求队列)和 outqueueRequests(外部请求队列)两个 ArrayList 类型的属性,以及一个 Elevator1 类型的引用 elevator。
方法:
构造方法:接收一个 Elevator1 对象作为参数,初始化请求队列,并将传入的电梯对象赋值给 elevator。
addRequest 方法:使用正则表达式判断请求格式(内部请求 <楼层数>,外部请求 <楼层数,UP|DOWN>)。对于符合格式的请求,先检查楼层是否在电梯可到达范围内(调用 isValidFloor 方法),并且判断是否为重复请求(与队列中最后一个请求比较),然后将请求添加到相应的队列中。
isValidFloor 方法:根据传入的楼层数,结合电梯的最小和最大楼层,判断该楼层是否在合法范围内,返回 true 或 false。
获取属性的方法:提供了 get 和 set 方法,用于获取和设置请求队列属性。
ElevatorController 类:
属性:有 Elevator1 类型的 elevator 对象、RequestQueue 类型的 requestQueue 对象、Request 类型的 a 对象以及一个计数器 number。
方法:
构造方法:接收 minFloor 和 maxFloor 作为参数,创建 Elevator1 对象、RequestQueue 对象和 Request 对象,并初始化 number 为 1。
addRequest 方法:将接收到的请求转发给 requestQueue 的 addRequest 方法,实现请求的添加。
run 方法:是电梯调度的核心逻辑。通过一个 while 循环,只要内部或外部请求队列不为空,就持续处理请求。根据请求队列的不同情况(内部为空外部不为空、外部为空内部不为空、内外都不为空),分别处理请求。当内外请求都不为空时,通过比较内部和外部请求的目标楼层与当前楼层的距离和方向关系,按照电梯运行规则(优先处理同方向请求等)决定先处理哪个请求。处理完请求后,更新电梯的当前楼层,并从请求队列中移除已处理的请求。
show 方法:根据电梯的起始楼层、目标楼层和运行方向,输出电梯运行过程中经过的每一层的当前楼层和运行方向信息。在到达目标楼层时,输出开门和关门信息。根据请求队列的状态(只有一个队列有请求或两个队列都有请求),调整输出格式。
Request 类:
方法:
getOutDirection 方法通过正则表达式从电梯外部请求字符串中提取乘梯方向("UP" 或 "DOWN");
getFloor 方法根据请求字符串的格式(内部请求和外部请求格式不同),通过正则表达式匹配或字符串截取的方式,提取出目标楼层数。
Main 类:
方法:
方法 main:使用 Scanner 从控制台读取用户输入的最小楼层、最大楼层和一系列请求。创建 ElevatorController 对象,并将用户输入的请求通过 controller.addRequest 方法添加到请求队列中。最后调用 controller.run 方法启动电梯的运行。
代码规模:

类图如下:

复杂度分析:

在ElevatorController.run()中复杂度为 5,语句数 13,最大深度 3,调用次数 18 。是电梯运行核心调度方法,该复杂度相对合理,但语句数和调用次数较多,逻辑有一定复杂性。涉及多种请求情况判断、电梯状态更新及与其他类交互。
在RequestQueue.addRequest()中复杂度 11,语句数 15,最大深度 是4,调用次数 20 。此方法负责处理请求添加,复杂度较高。
在Request.getFloor() 和 Request.getOutDirection()中的复杂度均为 3,语句数 7,最大深度 4 。这两个方法用于解析请求相关信息,复杂度还行,但最大深度 4 表明控制流有一定嵌套。
其他方法复杂度大多为1,语句结构简单。
从雷达图上看的话,代码平均复杂度和最大复杂度较高,代码逻辑较为复杂。注释很少,代码可读性很低。
采坑心得:
数据处理方面,输入校验存漏洞,未充分考虑非法楼层及间隔性重复请求;ElevatorController 类承担了过多功能,与其他类交互频繁且逻辑混乱,不利于代码的理解和维护。各相关类之间存在较强耦合,一个类出错会导致另一个类出错。
改进建议:
对输入进行更全面的合法性检查;优化类设计结构将 ElevatorController 类的功能进一步拆分,降低类间耦合度,让代码可以更好的维护。
第三次作业:
要求:
对第二次电梯调度程序再次迭代设计,需遵循单一职责原则。新增乘客类,取消原乘客请求类。设计包含电梯类、乘客类、队列类及控制类。电梯运行规则基本不变,乘客请求输入变动,外部请求格式改为 <请求源楼层,请求目的楼层> ,且电梯处理外部请求后,将其目的楼层加入内部请求队列队尾。
电梯运行逻辑:
内部请求为空外部不为空时,我就执行外部的,然后我把外部请求去的楼层转为内部请求,也要判断他跟此时内部请求最后一个一不一样;
外部请求为空,内部请求不为空时,我就执行内部的;
都不为空的时候,看两个请求的队头,当内部请求和外部请求的楼层在当前的楼层同一侧就是都在上侧或者都在下侧(大条件)
如果外部楼层离当前楼层近,(小条件)
(光近还不行,内外的请求楼层在当前楼层上面,且外部要去的楼层需要方向为上或者内外请求楼层在当前楼层下面,外部楼层需要去的楼层方向为下)才会先去外部请求的楼层,然后把外部的想去的楼层转为内部请求,别的情况都会先去内部请求的楼层。
如果内外发出请求的楼层相等(小条件)
然后把外部的目的楼层转为内部请求,俩个都执行,然后把外面的目的楼层添加到内部请求,也要判断他跟此时内部请求最后一个一不一样;
如果内部请求离当前楼层近,(小条件)
无论如何都先去内部请求楼层
内部和外部请求不在同一侧的话(大条件)
一是在当前楼层此时电梯方向向上,外层请求在当前楼层上方,外部请求的方向是上(目的楼层减去当前楼层大于0)时,去外部请求的楼层,然后把外部的目的楼层转为内部请求,也要判断他跟此时内部请求最后一个一不一样;
二是当前楼层此时电梯方向向上,外部请求在当前楼层上面,且外部请求的方向是下(目的楼层减去当前楼层小于0)时,去外部请求的楼层,然后把外部的目的楼层转为内部请求,也要判断他跟此时内部请求最后一个一不一样;
三是都是先去内部请求。
电梯实现方法:
Elevator1 类:
属性:包含 maxFloor(最大楼层)、minFloor(最小楼层)、currentFloor(当前楼层)、direction(运行方向)、runningState(运行状态)。
方法:
构造方法:接收 minFloor 和 maxFloor 作为参数,初始化电梯的基本属性,如将 currentFloor 设置为 minFloor,direction 设置为 "IDLE",runningState 设置为 "STOPPED"。
方法:提供了一系列 get 和 set 方法,用于获取和设置电梯的各个属性,方便其他类对电梯状态进行访问和修改。
RequestQueue 类:
属性:有 inqueueRequests(内部请求队列)和 outqueueRequests(外部请求队列)两个 ArrayList 类型的属性,以及一个 Elevator1 类型的引用 elevator。
方法:
构造方法:接收一个 Elevator1 对象作为参数,初始化请求队列,并将传入的电梯对象赋值给 elevator。
addRequest 方法:使用正则表达式判断请求格式(内部请求 <楼层数>,外部请求 <请求源楼层,请求目的楼层> )。对于符合格式的请求,先检查楼层是否在电梯可到达范围内(调用 isValidFloor 方法),并且判断是否为重复请求(与队列中最后一个请求比较),然后将请求添加到相应的队列中。
isValidFloor 方法:根据传入的楼层数,结合电梯的最小和最大楼层,判断该楼层是否在合法范围内,返回 true 或 false。
获取属性的方法:提供了 get 和 set 方法,用于获取和设置请求队列属性。
ElevatorController 类:
属性:持有 Elevator1 类型的 elevator 对象、RequestQueue 类型的 requestQueue 对象、Passenger 类型的 a 对象以及一个输出第一层状况的 number。
方法:
构造方法:接收 minFloor 和 maxFloor 作为参数,创建 Elevator1 对象、RequestQueue 对象和 Passenger 对象,并初始化 number 为 1。
addRequest 方法:将接收到的请求转发给 requestQueue 的 addRequest 方法,实现请求的添加。
run 方法:。通过一个 while 循环,只要内部或外部请求队列不为空,就持续处理请求。根据请求队列的不同情况(内部为空外部不为空、外部为空内部不为空、内外都不为空),分别处理请求。当处理外部请求时,电梯到达请求源楼层后,将请求目的楼层作为新的内部请求添加到内部请求队列队尾,然后移除已处理的外部请求。当内外请求都不为空时,通过比较内部和外部请求的目标楼层与当前楼层的距离和方向关系,按照电梯运行规则(优先处理同方向请求等)决定先处理哪个请求。处理完请求后,更新电梯的当前楼层,并从请求队列中移除已处理的请求。
show 方法:根据电梯的起始楼层、目标楼层和运行方向,输出电梯运行过程中经过的每一层的当前楼层和运行方向信息。在到达目标楼层时,输出开门和关门信息。根据请求队列的状态(只有一个队列有请求或两个队列都有请求),调整输出格式。
Passenger 类:
属性:包含 sourceFloor(请求源楼层)和 destinationFloor(请求目的楼层)。
方法:
getOutDirection 方法通过正则表达式从外部请求字符串中提取并判断乘梯方向(根据请求源楼层和目的楼层比较得出 "UP" 或 "DOWN")。
getFloor 方法根据请求字符串的格式(内部请求和外部请求格式不同),通过正则表达式匹配或字符串截取的方式,提取出请求源楼层(对于外部请求)或目标楼层(对于内部请求)。
getDestinationFloor 方法从外部请求字符串中提取请求目的楼层。
Main 类:
方法:
方法 main:使用 Scanner 从控制台读取用户输入的最小楼层、最大楼层和一系列请求。创建 ElevatorController 对象,并将用户输入的请求通过 controller.addRequest 方法添加到请求队列中。最后调用 controller.run 方法启动电梯的运行。
代码规模:

类图如下:

复杂度分析:

ElevatorController.run():复杂度为 6,语句数 16,最大深度 4,调用次数 21 。作为电梯运行核心调度方法,其复杂度较高,逻辑分支较多。
RequestQueue.addRequest():复杂度为 11,语句数 15,最大深度 4,调用次数 20 。该方法负责处理请求添加,需通过正则表达式判断请求格式,还要检查楼层有效性和请求重复性,涉及多个条件判断和逻辑分支,复杂度高。
其他的方法复杂度大多为1,语句结构简单,功能单一。
从雷达图看,代码中方法整体复杂程度处于中等水平,但存在部分复杂度较高的方法拉高了平均值,有一定嵌套深度,部分方法逻辑层次较复杂;
注释占比小,可读性不强。
采坑心得:
数据处理方面,请求格式校验存在漏洞,对非法字符组合处理不足,测试中发现大量请求未被正确过滤;类设计结构上,ElevatorController 类职责耦合度高,与其他类交互复杂,Passenger 类功能分散,方法存在代码冗余。
改进建议:
需要进一步完善数据校验逻辑,要严格校验请求格式;优化类设计结构,将 ElevatorController 类的功能进一步拆分,使其职责更加单一,并对 Passenger 类的方法进行重构,消除代码冗余。
三、总结
通过三次电梯题目集,对这个面向对象的编程框架更加熟悉,特别是题集6开始的单一职责的应用,将不同的功能拆分到不同类中,让代码结构更加的清晰,并且可维护度好。同时学会了利用arraylist来管理队列,和利用正则表达式来匹配乘客请求,提取乘客请求信息。同时也学会根据范例,来不断分析电梯的运行规则,总结它的运行规律。
需要进一步优化的地方:
在算法上:当前的电梯调度算法虽然能满足题目要求,但在处理复杂请求时可能效率不高。可以进一步研究更高效的调度算法,像电梯的请求的准确匹配、队列运行优化等来提高电梯运行效率。
在接受请求上:在发出请求时,可能同时发出,但当前代码只能实现一个一个接受,不能满足多个乘客同时发起请求,应该实现并发处理请求,提高系统的响应速度。
在原则上:虽然在代码中遵循了单一职责原则,但是在电梯控制类里面有太多的复杂逻辑,与其他类耦合度高。可以将 ElevatorController 类的功能进一步拆分,使其职责更加单一。

posted @ 2025-04-19 20:24  一抹淡影  阅读(73)  评论(0)    收藏  举报