BLOG1

news/2025/11/22 19:36:24/文章来源:https://www.cnblogs.com/lasasd/p/19256205

一、前言
知识点覆盖:三次作业逐步引入了类的封装与继承、集合框架(ArrayList、HashSet、Deque等)的应用、单一职责原则(SRP)的实践、请求队列的管理、调度算法的优化,以及输入输出的高效处理。此外,还涉及边界情况处理、请求去重、状态机管理等工程实践要点。
题量与难度:题量呈递增趋势,从第一次作业的基础功能实现,到第二次作业的类职责拆分,再到第三次作业的真实场景模拟。难度上,第一次作业聚焦 “能用”,第二次作业强调 “合理”,第三次作业追求 “健壮”,逐步从功能实现深化到设计优化。
核心目标:通过三次迭代,最终实现一个遵循面向对象设计原则、逻辑清晰、可维护性强的单部电梯调度系统,能够正确处理内部 / 外部请求、遵循 “同向优先” 调度规则,并准确输出运行日志。

二、设计与分析
2.1 第一次作业:基础实现与职责耦合
2.1.1 类图设计
第一次作业的类设计较为简单,核心是Elevator类,承担了所有核心职责:
Request(抽象基类)、InternalRequest、ExternalRequest:封装请求信息(楼层、方向)。
Elevator类:包含电梯状态(当前楼层、方向、最大 / 最小楼层)、请求队列(内部请求ArrayList、外部上行 / 下行请求ArrayList),并实现了请求添加、调度决策(processRequests)、移动(move)、开关门等所有行为。
Main类:负责输入解析和输出触发。

2.1.2 核心调度算法
调度逻辑集中在Elevator.processRequests()方法,核心规则是 “同向优先”:
1.检查当前方向(UP/DOWN),遍历同方向的内部 / 外部请求,找到最近的目标楼层。
1.若当前方向无请求,切换方向并查找目标。
1.移动到目标楼层,处理该楼层的所有请求(移除队列),开关门。
2.1.3 复杂度分析(基于代码结构与工具逻辑推导)
采用循环复杂度(v (G))、结构化复杂度(ev (G))、设计复杂度(iv (G))作为核心指标,结合代码职责与逻辑分支推导如下:
image

类复杂度汇总:
image

仅一个核心方法,因输入解析与异常处理导致复杂度略高
关键方法分析:Elevator.processRequests()的 v (G) 达 12,ev (G) 为 4,说明该方法逻辑分支多(需覆盖方向判断、队列状态、目标筛选等场景),但结构化程度中等(未出现严重 “病态” 嵌套);iv (G) 为 8,反映该方法与电梯内部状态(当前楼层、方向)、请求队列的耦合度极高,符合其 “职责集中” 的设计缺陷。

2.2 第二次作业:职责拆分与单一职责原则实践
2.2.1 类图设计
第二次作业的核心改进是拆分Elevator类的职责,引入ElevatorQueues和ElevatorController类,遵循单一职责原则:
Request相关类:保留第一次作业的设计,封装请求信息。
ElevatorQueues类:专门负责请求队列管理(添加请求、去重、获取队头、处理当前楼层请求),使用Deque(保证队头优先)和HashSet(去重)。
Elevator类:仅负责电梯的物理状态(当前楼层、方向)和物理行为(移动、开关门、边界转向),不再管理请求队列。
ElevatorController类:核心调度器,协调Elevator和ElevatorQueues,实现调度决策(确定目标楼层、切换方向)。
Main类:仅负责输入解析和控制器启动。
类图结构:
image

2.2.2 核心调度算法
调度逻辑迁移到ElevatorController.run()方法,核心优化是队列与调度分离:
1.控制器读取电梯当前状态(楼层、方向)和队列状态(队头请求)。
1.优先查找当前方向的有效请求(内部队头楼层≥当前楼层(UP 方向)或≤当前楼层(DOWN 方向),外部队头方向一致且楼层符合)。
1.若当前方向无请求,计算内部 / 外部队头与当前楼层的距离,选择最近的请求作为目标,并切换方向。
1.控制电梯移动到目标楼层,调用ElevatorQueues.processCurrentFloor()处理请求,开关门。
2.2.3 复杂度分析(基于代码结构与工具逻辑推导)
职责拆分后,复杂度分布更均衡,核心指标如下:
image
类复杂度汇总:
image

关键方法分析:ElevatorController.run()的 v (G) 为 10,较第一次作业的processRequests降低 2,ev (G) 保持 4,说明职责拆分后,调度逻辑的分支减少、结构化程度更优;iv (G) 为 7,反映控制器与电梯、队列的耦合度合理(符合 “协调者” 角色定位)。ElevatorQueues.processCurrentFloor()的 v (G) 为 6,是队列类的核心方法,负责请求处理与去重,逻辑聚焦且无过度嵌套。

2.3 第三次作业:
2.3.1 类图设计
第三次作业的核心改进是引入Passenger类替代Request类,完善调度逻辑:
Passenger类:封装乘客的源楼层(外部请求)、目的楼层(内部请求),提供方向判断(getSourceFloor() < getTargetFloor() → UP),并通过equals()和hashCode()实现请求去重(同一源 + 目的视为同一请求)。
ElevatorQueues类:调整为管理 “内部目的楼层队列”(Deque)和 “外部乘客队列”(Deque),处理当前楼层请求时,返回上车的乘客(用于后续添加目的楼层到内部队列)。
Elevator类:保持物理行为职责,优化移动逻辑(使用StringBuilder批量输出日志,提升效率)。
ElevatorController类:完善调度逻辑,正确处理 “同向优先 + 顺路优先”,并在乘客上车后自动添加目的楼层到内部队列。
Main类:优化输入解析,支持外部请求格式从<楼层,方向>改为<源楼层,目的楼层>(更真实)。
类图结构:
image

2.3.2 核心调度算法
调度逻辑在ElevatorController.run()中进一步完善,核心规则是 “同向优先 + 顺路优先 + 真实乘客行为”
1.控制器读取电梯状态和队列状态(内部队头目的楼层、外部队头乘客)。
1.优先查找当前方向的 “顺路请求”:
UP方向:内部队头目的楼层≥当前楼层,外部队头乘客方向为UP且源楼层≥当前楼层,选择其中最近的楼层作为目标。
DOWN方向:内部队头目的楼层≤当前楼层,外部队头乘客方向为DOWN且源楼层≤当前楼层,选择其中最近的楼层作为目标。
1.若当前方向无顺路请求,计算所有队头请求与当前楼层的距离,选择最近的请求作为目标,切换方向。
1.电梯移动到目标楼层,调用ElevatorQueues.processCurrentFloor()处理请求:
内部请求:移除队头目的楼层。
外部请求:移除队头乘客,返回该乘客(控制器自动将其目的楼层添加到内部队列)。
1.若有请求处理,开关门;重复上述流程直到所有请求处理完毕。
2.3.3 复杂度分析(基于代码结构与工具逻辑推导)
引入Passenger类后,逻辑更贴近真实场景,但通过合理的职责划分,复杂度仍保持可控:
image
类复杂度汇总:
image

关键方法分析:ElevatorController.run()的 v (G) 为 11,较第二次作业增加 1,因新增 “乘客上车后添加目的楼层” 逻辑,但 ev (G) 仍保持 4,说明结构化程度未下降;iv (G) 为 8,反映控制器需协调电梯、队列、乘客三类对象,耦合度合理。Passenger.equals()的 v (G) 为 3,因需比较源 / 目的两个属性,是保证请求去重的关键方法,逻辑必要且无冗余。

三、采坑心得
3.1 第一次作业:基础逻辑与边界处理问题
问题 1:调度方向判断错误
当电梯在中间楼层(如 5 楼),当前方向为UP,但内部请求有 3 楼(DOWN方向)时,错误地切换方向处理 3 楼请求,违反 “同向优先” 规则。
解决:在查找目标时,严格筛选当前方向的请求(UP方向仅查找楼层≥当前楼层的请求,DOWN方向仅查找楼层≤当前楼层的请求)。

3.2 第二次作业:职责拆分后的逻辑漏洞(答案仅对一半)

问题 1:“最近请求” 判断错误
调度逻辑中仅比较 “内部队头” 和 “外部队头” 与当前楼层的距离,未考虑队列中其他顺路请求。例如:当前楼层 3,UP方向,内部队列是[5,4],外部队列是[6,UP],错误地选择 5 作为目标(队头),而实际应优先处理 4(更近的顺路请求)。
原因:使用Deque的peekFirst()仅获取队头,未遍历队列查找顺路的最近请求。
解决(第三次作业):在ElevatorQueues中提供 “查找当前方向顺路最近请求” 的方法,或在控制器中遍历队列筛选目标(第三次作业通过优化run()方法的minUp/maxDown计算实现)。
问题 2:外部请求处理不完整
ElevatorQueues.processCurrentFloor()仅处理队头的外部请求,若同一楼层有多个同方向请求(虽HashSet去重,但极端情况下队列中可能存在多个有效请求),导致部分请求未处理。
解决(第三次作业):修改processCurrentFloor()为循环处理当前楼层的所有有效请求(直到队头不再是当前楼层或方向不一致),确保无遗漏。
问题 3:边界转向逻辑缺陷
电梯到达最高层(如 10 楼)后,未强制切换方向为DOWN,导致继续查找UP方向请求(无结果),陷入死循环。
解决:在Elevator类中添加forceTurnAtBoundary()方法,到达边界楼层时自动切换方向,控制器每次调度前调用。

3.3 第三次作业:完善逻辑与性能优化
问题 1:输入解析格式错误
第三次作业外部请求格式从<楼层,方向>改为<源楼层,目的楼层>,最初未适配新格式,导致输入解析失败。
解决:修改Main类的输入解析逻辑,判断content包含,时,拆分源楼层和目的楼层,创建Passenger对象。
问题 2:日志输出效率低
最初每次移动楼层都调用writer.write()(I/O 操作频繁),导致大数据量请求时超时。
解决:在Elevator.moveTo()中使用StringBuilder拼接所有移动日志,最后一次性写入,减少 I/O 次数,提升性能。

3.4 测试用例设计的重要性
三次作业的调试过程中,边界测试用例和复杂场景测试用例是发现问题的关键:
边界用例:最小楼层(1 楼)、最大楼层(如 20 楼)、请求楼层等于当前楼层、仅外部请求、仅内部请求。
复杂场景用例:多请求交叉(如<3,UP>→<5>→<6,DOWN>→<7>→<3>)、同向多请求(如<4,UP>→<5,UP>→<3,UP>)、反向请求穿插(如<5,UP>→<2,DOWN>→<6,UP>)。
例如,通过测试用例:
1
5
3,5> // 外部请求:3楼上车,5楼下车
<4,2> // 外部请求:4楼上车,2楼下车
<5,1> // 外部请求:5楼上车,1楼下车
end
验证了 “同向优先” 和 “乘客目的楼层添加” 的正确性,确保电梯先处理 3→5 的UP请求,再处理 5→4→2→1 的DOWN请求。

四、改进建议(可持续优化方向)
4.1 代码可扩展性优化
引入策略模式(Strategy Pattern)处理调度算法
目前调度逻辑固定在ElevatorController.run()方法中,若需添加新调度规则(如 “最短等待时间优先”“最大载客量优先”),需修改run()方法,违反 “开闭原则”。
改进:定义Scheduler接口(如getTargetFloor(Elevator elevator, ElevatorQueues queues)),实现不同调度策略(SameDirectionScheduler、ShortestDistanceScheduler等),控制器通过依赖注入选择策略,无需修改核心逻辑。
使用枚举类优化方向状态
目前方向用String("UP"/"DOWN")表示,易出现拼写错误(如"Up"),且判断逻辑繁琐(if (direction.equals("UP")))。
改进:定义Direction枚举(UP, DOWN),使用switch判断方向,提升代码可读性和健壮性。
4.2 性能优化
使用更高效的数据结构优化目标查找
目前查找顺路最近请求需遍历队列(O (n)),请求量大时效率较低。
改进:在ElevatorQueues中为内部 / 外部请求维护TreeSet(有序集合),按楼层排序:
内部请求TreeSet:按楼层升序,UP方向查找≥当前楼层的最小元素(ceiling(currentFloor)),DOWN方向查找≤当前楼层的最大元素(floor(currentFloor))。
外部请求TreeSet:按源楼层升序,按方向分组,查找逻辑同内部请求。
有序集合的查找效率为 O (log n),大幅提升调度性能。
异步处理输入与调度
目前输入解析和调度是串行的(输入全部读取后才启动调度),无法处理动态输入(如实时添加请求)。
改进:使用多线程,主线程负责输入解析并添加请求到队列,调度线程循环处理队列,实现异步响应。

五、总结
5.1 学习收获
通过三次电梯调度作业的迭代实践,我在以下方面取得了显著进步:
面向对象设计能力:从职责耦合到单一职责原则的实践,理解了 “高内聚、低耦合” 的重要性,学会了如何拆分类的职责,提升代码可维护性。从第一次作业Elevator类包揽所有职责(WMC=25),到第三次作业各分类职责明确(Elevator WMC=9、Controller WMC=13),深刻体会到合理的类设计对代码质量的决定性作用。
问题分解与建模能力:将复杂的电梯调度问题分解为 “请求管理”“物理行为”“调度决策” 三个核心模块,逐步构建符合真实场景的模型(从Request到Passenger)。
工程实践能力:掌握了集合框架的灵活应用(Deque保证队头优先、HashSet去重、TreeSet有序查找)、边界情况处理、输入输出优化、测试用例设计等工程技巧。同时,通过复杂度分析,学会了识别代码中的 “热点” 方法(如processRequests、run),并针对性优化。
调试与优化思维:通过分析测试失败原因,学会了定位逻辑漏洞(如调度方向判断错误),并从 “能用” 到 “好用”(性能优化、可读性提升)进行持续优化。

5.2 需进一步学习的内容
多线程与并发编程:目前电梯调度是串行的,实际电梯系统需处理并发请求(如同时按下多个按钮),需学习多线程同步(synchronized、Lock)、线程池等知识,实现并发调度。
设计模式的综合应用:除策略模式外,可学习观察者模式(如请求添加时通知调度器)、工厂模式(如创建不同类型的Passenger),进一步提升代码可扩展性。
性能分析与优化工具:学习使用 SourceMonitor(复杂度分析)、VisualVM(内存与 CPU 分析)等工具,量化评估代码质量,针对性优化性能瓶颈。

5.3 课程与作业改进建议
作业迭代的引导性增强:第二次作业的 “职责拆分” 目标明确,但缺乏对 “调度逻辑优化” 的引导(如如何正确查找顺路请求),导致部分同学陷入逻辑漏洞。建议在作业说明中补充 “调度算法要点”(如 “顺路优先的判断标准”),或提供参考伪代码。
测试用例公开化:目前测试点仅在提交后可见,调试效率低。建议提供部分公开测试用例(如边界用例、复杂场景用例),帮助同学提前验证逻辑,减少提交次数。
增加实践案例分享:课程中可增加优秀作业的设计分析(如类图、调度算法),或组织小组讨论,分享不同的实现思路(如数据结构选择、职责拆分方式),拓宽视野。
引入真实场景扩展:第三次作业已贴近真实场景,可进一步扩展为 “多部电梯调度”“实时监控界面” 等,结合 GUI(如 Swing/JavaFX)或 Web 技术,提升学习兴趣和综合应用能力。

5.4 结语
三次电梯调度作业的迭代过程,是从 “功能实现” 到 “设计优化” 的思维转变过程。我深刻体会到,面向对象编程的核心不仅是语法的运用,更是 “如何将现实问题抽象为类和对象,如何通过合理的职责拆分构建健壮、可维护的系统”。未来,我将继续深化对设计原则和模式的理解,在实践中不断提升自己的软件设计与开发能力。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/973359.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

host with linux

在 Linux 系统中,"host" 通常指的是 主机(主机名),即一个计算机的名称。在 Linux 系统中,主机名可以通过 hostname 命令查看或修改。一、查看当前主机名hostname或者echo $HOSTNAME这两个命令的功能是一…

深入解析:算法基础篇(8)贪心算法

深入解析:算法基础篇(8)贪心算法2025-11-22 19:33 tlnshuju 阅读(0) 评论(0) 收藏 举报pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block !imp…

详细介绍:【STM32】工程文件管理

pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block !important; font-family: "Consolas", "Monaco", "Courier New", …

南昌航空大学-ptajava

前言 本次对PTA作业进行总结,共三道Java大题,为电梯调度程序的迭代开发。涉及到基础Java语言的运用,look电梯调度算法的实现,队列结构的使用,枚举类型运用,类设计,迭代开发能力等知识点。 第一次作业:单部电梯…

sguardsvc64.exe(Anti-Cheat Expert)驱动不兼容导致无法开启“内核模式硬件强制堆栈保护”或“内存完整性”

windows安全感中心,有时候会提示无法开启“内核模式硬件强制堆栈保护”或“内存完整性”。打开详情会显示sguardsvc64.exe的原因,这个其实是腾讯反作弊系统相关的文件。大概率你是一个腾讯游戏玩家。刚开始网上搜索如…

Wi-Fi FTM 技术 10 年后展望

1. 技术成熟背景 假设 10 年后,全球 Wi-Fi AP 生态全面升级,所有 AP 都支持 IEEE 802.11mc/ax FTM 功能,同时绝大多数智能手机和平板、IoT 设备也原生支持 FTM 测距。这意味着:用户设备无需额外硬件即可实现高精度…

Docker使用【镜像】 - 指南

pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block !important; font-family: "Consolas", "Monaco", "Courier New", …

20251122

在我的世界forge版本的mod开发中,虽然总体逻辑不难,但要记住的方法和类名一大堆,要是想上手得多写多看啊

2025年11月22日训练赛

F1. Cycling (Easy Version) #include<bits/stdc++.h> using namespace std; #define endl \n #define yes cout << "Yes" << endl #define no cout << "No" << en…

Python 潮流周刊#128:将 Rust 语言引入 CPython

本周刊由 Python猫 出品,精心筛选国内外的 400+ 信息源,为你挑选最值得分享的文章、教程、开源项目、软件工具、播客和视频、热门话题等内容。愿景:帮助所有读者精进 Python 技术,并增长职业和副业的收入。 温馨提…

NCHU_单部电梯调度程序总结blogs

一、前言 这三次作业虽然都围绕着同一个主题——“单部电梯调度”,但每一次都在逼着我更深入地理解面向对象设计、系统分层思想和程序可维护性这些看似抽象但又极其实用的概念。 知识点: 基础的 面向对象编程(类、属…

AI填补核聚变传感器数据空白技术解析

普林斯顿大学开发的新型AI工具Diag2Diag通过生成合成数据填补等离子体诊断空白,该技术能减少对大型硬件的依赖,使未来聚变反应堆更紧凑可靠,同时适用于航天器和机器人手术等领域。AI填补核聚变传感器数据空白技术解…

电梯调度程序分析

一.前言本次博客将完整复盘电梯调度系统的三次迭代开发历程。第一次迭代聚焦核心功能落地,以单一电梯类封装所有状态、队列与调度逻辑,实现 “同向优先、逐层停靠” 的基础运行规则,解决 “能跑起来” 的核心问题;…

Hive动态分区怎样减少存储压力

Hive动态分区是一种根据数据量自动创建分区的功能,它可以有效地减少小文件的数量,从而提高查询性能。然而,动态分区也可能导致存储压力增加,因为它会生成大量的分区文件。为了减少存储压力,可以采取以下策略:调整…

dockers拉取redis镜像

1.修改 Docker 配置文件 vim /etc/docker/daemon.json 2.添加国内镜像源 将以下内容写入文件(选择阿里云、网易云等镜像): { "registry-mirrors": ["https://dh-mirror.gitverse.ru", "ht…

面向对象程序设计——单元总结

前言 这次的三个单部电梯调度实验是层层递进的。从第一个作业的一个“上帝类”Elevator类;到第二个作业的解决实验一中“职责过多”的问题,遵循SRP,将不同的职责拆分到不同的类中,从而引入Request类、Queue类、Con…

Linux命令绕过 - 教程

pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block !important; font-family: "Consolas", "Monaco", "Courier New", …

帮同学签了个到,我发现竟然能盗光他所有账号

你的数字生活,可能正悬在一根头发上。 我们先做一个简单的灵魂拷问:你所有网络账号的密码,是不是都在用那么两三个“老伙计”轮换?或者更糟糕一点,你是不是在用同一个密码,通行于淘宝、微信、Steam 和那个不知名…

MyBatis Flex 讲解使用

目录1 MyBatis Flex1.1 简介1.2 简单操作1.2.1 配置1.2.1.1 pom.xml1.2.1.2 yml配置1.2.2 生成代码1.2.3 业务类1.2.3.1 实体1.2.3.2 实体脱敏1.2.3.3 Mapper接口1.2.3.4 Service层1.3 MyBatis-Flex 核心 API1.3.1 条件…

Catalog

东西有点杂,稍微整理一下。 Algorithm Introduction【老】Splay 浅谈