航空器配载与货运管理系统
一、前言
作业集概览
本学期JAVA课程的前三次作业是一个循序渐进的迭代开发过程,围绕航空器配载与货运管理这一真实业务场景展开。从第一次作业的基础货物装载,到第二次作业的多货舱管理,再到第三次作业的配平计算与重心评估,让我第一次系统地体验了面向对象分析与设计的完整流程,也深刻理解了单一职责原则(SRP)、组合与聚合关系、依赖关系等核心设计原则在实际开发中的重要性。
难度分析
SRP设计、链表排序、输入格式处理。
组合/聚合关系、浮点精度、稳定排序。
物理公式、多重验证、边界条件、冒泡排序/选排/快排。
个人感受:
第一次作业最大的挑战在于理解并应用单一职责原则(SRP)。
第二次作业在第一次的基础上增加了多货舱管理和组合/聚合关系的设计要求。
第三次作业则是前两次的综合应用,同时引入了物理计算公式和复杂的输入验证逻辑。
三次作业难度逐级递增,让我完整经历了从“会写代码”到“会设计代码”的转变过程。
二、设计与分析
第一次作业:
1.题目回顾
设计一个基础的航班货运配载模块。系统需要记录航班的基本信息(航班号、最大起飞重量、最大业载重量)。地勤人员可以按照货物重量从高到低向该航班添加货物(货物名称、重量)。系统需要实时计算当前已装载的总重量,并判断是否超载。
2.知识点:
类的基本定义与封装(private属性、public方法)
构造方法的重载与使用
基本输入输出处理(Scanner的nextLine()陷阱)
排序算法(选择排序/比较器排序)
链表数据结构的基本操作
单一职责原则(SRP)的初步理解
3.代码分析:
代码规模

类图如下(修改后):

作业明确要求类设计必须符合单一职责原则(SRP),参考类图如下所示。类设计如果违背了SRP,此题不得分。
由于第一次做题时不熟悉SRP,我只使用了一个Main类,将其他类放在了Main类里,不符合封装性,此后作业将格外注意这一点。
第二次作业:
1.题目回顾
在第一次作业的基础上,航空公司要求进一步细化配载管理。飞机不再只有一个货舱,而是分为多个货舱(如前舱、后舱等)。每个货舱有独立的最大载重和固定数量的装载位置(行列网格)。地勤人员需要按照货物重量从高到低的顺序,将每件货物选择放入某个货舱,系统需实时检查该货舱是否超载。
2.知识点:
组合关系与聚合关系的区分(Position与CargoCompartment是组合,CargoCompartment与Cargo是聚合)
集合框架的熟练使用(ArrayList、HashMap、Collections.sort)
比较器接口与Lambda表达式
浮点数精度处理(容差比较)
多货舱管理的数据结构设计
业务逻辑与输入输出分离的架构模式
3.代码分析:
代码规模

类图如下

本次作业存在两个隐藏测试点未通过,仍未解决
两个未通过测试点的问题分析
经过仔细排查,我发现代码中存在以下几个潜在问题:
问题1:LoadDispatcher类中的sortCargos方法未被使用但存在
java
public List
// 使用选择排序实现,但这个方法从未被调用
// Main中实际使用的是Lambda排序
}
虽然不影响功能,但这个未使用的方法表明设计上存在冗余。某些评测系统可能会检测方法覆盖率或代码质量。
问题2:浮点数直接比较的不安全性
在Lambda排序中double类型直接使用!=比较存在精度风险。虽然在这个场景中货物重量是输入的确定值(如850.0、500.0),理论上不会有精度问题,但某些边界情况(如重量为0.1+0.2)可能导致意外结果。
问题3:货舱查找失败时的处理不够明确
如果输入的货舱ID不存在,程序会输出装载失败。但根据题目描述,输入保证合法,所以这个逻辑理论上不会触发。
问题4:InputValidator类未被使用
题目要求实现InputValidator类,但我的代码中只是定义了它,从未实际调用其校验方法。某些测试点可能检查是否使用了输入校验。
问题5:输出格式中空行的处理
我的代码在货物装载结果后输出了一个空行,但观察题目样例输出,空行是存在的。如果评测系统对空格/换行敏感,可能导致格式错误。
第三次作业:
1.题目回顾
在第二次作业的基础上,引入旅客及其行李管理,并增加基于物理力矩的载重平衡计算功能。系统需要计算飞机重心位置,并换算为占平均空气动力弦(MAC)的百分比,判断是否在安全范围内。
2.知识点:
物理公式的编程实现(力矩、重心、百分比MAC计算)
组合关系的深入应用(Passenger与Luggage的组合)
依赖关系设计(WeightBalanceCalculator依赖Flight)
冒泡排序算法的实现(禁止使用Lambda和Collections.sort)
输入验证与异常处理(范围检查、边界条件)
容量不足的预检机制
格式化输出(printf保留一位小数)
3.代码分析
代码规模

类图如下

本次作业存在三个测试点未通过(前舱容量不足测试、后舱容量不足测、输入数据范围非法(装载前舱货物数量)测试)均为边界条件的测试,说明我的边界值处理不完善,我将继续改进。
三、采坑心得
第一次作业的采坑记录
坑1:滥用nextLine()导致输入错位
问题现象:读取货物重量后,下一个货物的名称读取为空字符串。
原因分析:scanner.nextInt()读取整数后,会留下一个换行符\n在缓冲区中。
坑2:违背SRP导致0分
问题现象:功能完全正确,但得分0分。
教训总结:动手写代码前,先画类图、明确职责分配。这是本次作业最惨痛的教训。
坑3:浮点数比较精度问题
解决方案:使用容差比较 > maxWeight + 1e-9
第二次作业的采坑记录
坑4:浮点数直接比较导致排序不稳定
问题现象:重量相等的货物顺序不确定。
解决方案:使用originalIndex作为第二排序键。
坑5:InputValidator类未被使用
虽然定义了InputValidator类,但从未调用其方法。这违反了“不要定义无用代码”的原则。
第三次作业的采坑记录
坑6:容量不足警告信息格式错误
问题现象:前舱/后舱容量不足测试未通过。
原因分析:警告信息中显示的“当前载重”应该是添加前的值,而不是添加后的值。
坑7:边界值处理不完善
问题现象:输入数据范围非法测试未通过。
原因分析:当totalCargoCount = 0时,frontCargoCount只能为0。我的代码虽然检查了范围,但可能在错误信息格式上有细微差异。
解决方案:确保错误信息与题目要求完全一致,添加浮点容差比较。
坑8:旅客姓名的硬编码
虽然不影响功能,但Passenger类的name属性未被使用,造成资源浪费。
改进方案:简化Passenger类,只保留必要属性。
坑9:力臂值的判断方式
使用location字符串判断力臂值,虽然功能正确,但不够灵活。如果增加更多货舱,需要修改判断逻辑。
改进方案:使用货舱ID(1=前舱,2=后舱)进行判断,更符合题目描述。
四、改进建议
1.命名要规范
2.关键的业务逻辑要有注释说明
3.逻辑要严谨,不要遗漏
4.缺乏测试点时要多尝试,不能只依赖题目给的测试点
五、总结
本阶段学习收获
SRP单一职责原则:第一次作业的0分让我深刻理解了“一个类应该只有一个引起它变化的原因”。从此以后,我养成了先画类图、明确职责分配再写代码的习惯。
物理公式的编程实现:力矩、重心、百分比MAC的计算,让我体会到了编程在工程领域的实际应用。
组合与聚合关系:第二次作业让我理解了组合(同生共死)和聚合(独立存在)的区别。Position是CargoCompartment的组合,Cargo是CargoCompartment的聚合。
依赖关系设计:第三次作业中,WeightBalanceCalculator作为纯计算工具类,通过参数传递Flight对象,而不是持有Flight成员变量,体现了正确的依赖关系设计。
输入验证与异常处理:学会了如何设计健壮的输入验证机制,处理各种边界条件。
边界测试的重要性:三个未通过的测试点都是边界情况,说明边界测试是发现bug的关键。
错误信息格式:输出格式必须与题目要求完全一致,包括空格、换行、标点符号。
写在最后
三次作业,一个月的时间,从被判0分到理解SRP,从单一货舱到多货舱管理,从简单的重量计算到复杂的重心评估,我完成了一次重要的思维转变和能力提升。
这个过程充满挫折——有看到0分时的震惊和不甘,有调试边界条件时的困惑和挣扎,有测试点未通过时的沮丧,但也有最终理解设计原则时的豁然开朗,有看到正确输出时的成就感。
我记得第一次作业被判0分后,我反复看了三遍评分标准,才意识到“类设计必须符合单一职责原则”不是一句空话,而是硬性要求。于是我花了一整天重构代码,把120行的Main类拆分成了4个职责清晰的类。虽然这次重构不计入成绩,但这个过程让我真正理解了什么是“高内聚、低耦合”。
第三次作业的三个未通过测试点,让我认识到边界测试的重要性。容量不足时警告信息的格式、货物数量为0时的处理、浮点数比较的精度——这些都是容易被忽视但至关重要的细节。
这门课程教会我的不仅仅是JAVA语法,更重要的是如何思考问题、如何设计解决方案、如何验证自己的代码、如何关注边界条件。这些能力将伴随我整个职业生涯。
感谢老师和助教的辛勤付出。OO之路才刚刚开始,我会继续努力!
浙公网安备 33010602011771号