OPP第一次作业集总结
前言
三次作业的题量和难度逐步增加,每次刚接触时,我都会觉得较为困难,但三次结束后往回看,发现前面的作业集变得简单了。第一次作业仅需实现单一货舱的货物排序与超载判断,类图结构简单。第二次作业涉及多货舱、位置网格、货物按目标货舱装载,需设计组合/聚合关系,调度类分离排序与查找逻辑。第三次引入物理计算(重心、力矩、MAC百分比),要求严格的设计约束(禁用继承/多态),手写冒泡排序替代内置排序,同时增加旅客管理和输入校验,对代码组织和业务理解要求较高。
第一次作业
目标
设计一个基础的航班货运配载模块。系统需要记录航班的基本信息(航班号、最大起飞重量、最大业载重量)。地勤人员可以按照货物重量从高到低向该航班添加货物(货物名称、重量)。系统需要实时计算当前已装载的总重量,并判断是否超载。
设计与分析
看到题目后,首先明确核心需求:记录航班信息、按重量降序添加货物、实时计算总重并判断超载。需要四个实体类:Flight(航班号、最大业载)、Cargo(名称、重量)、LoadManifest(管理货物列表并提供添加、总重计算、超载判断)、Main(输入输出控制)。排序算法选择手写选择排序,因为题目强调“从高到低添加”。
算法
选择排序。
实现方法
使用ArrayList存储所有货物,读取完成后调用选择排序算法对货物按重量降序排列,最后遍历输出并判断是否超载
代码规模
第一次作业代码规模如下表
| Source File | Total Lines | Source Code Lines | Source Code Lines [%] | Comment Lines | Comment Lines [%] | Blank Lines | Blank Lines [%] |
|---|---|---|---|---|---|---|---|
| Flight.java | 12 | 11 | 91.7% | 1 | 8.3% | 0 | 0% |
| Cargo.java | 12 | 11 | 91.7% | 1 | 8.3% | 0 | 0% |
| LoadManifest.java | 30 | 27 | 90.0% | 1 | 3.3% | 2 | 6.7% |
| CargoSorter.java | 20 | 19 | 95.0% | 0 | 0% | 1 | 5.0% |
| Main.java | 34 | 30 | 88.2% | 2 | 5.9% | 2 | 5.9% |
| Total: | 108 | 98 | 90.7% | 5 | 4.6% | 5 | 4.6% |
类图
Flight航班类
2. Cargo货物类
3. LoadManifest装载清单类(管理货物列表、计算总重、判断超载)
4. CargoSorter货物排序类(选择排序,按重量降序)
5. Main主类(程序入口,输入输出)

时序图

复杂度分析
第一次作业的复杂度分析如下表
| 类名 | 总方法数 | 圈复杂度(总和) | 最大方法圈复杂度 | 平均方法圈复杂度 | 最大嵌套深度 | 代码行数(Source Line) |
|---|---|---|---|---|---|---|
| Flight | 3 | 3 | 1 | 1.0 | 1 | 11 |
| Cargo | 3 | 3 | 1 | 1.0 | 1 | 11 |
| LoadManifest | 6 | 8 | 2 | 1.33 | 2 | 27 |
| CargoSorter | 1 | 4 | 4 | 4.0 | 3 | 19 |
| Main | 1 | 2 | 2 | 2.0 | 2 | 30 |
| 总计/平均 | 14 | 20 | 4 | 1.43 | 3 | 98 |
可以看出CargoSorter的sortCargo方法复杂度较高,因为它本质上是手写了选择排序,是对Java内置排序方法不熟悉所导致。
踩坑心得
最初我使用的是冒泡排序来处理货物,但是测试点就是无法通过。后来我仔细观察题目,发现要按照货物重量从高到低向该航班添加货物,而冒泡排序是先添加了所有货物,再进行排序。将冒泡排序改为选择排序后,测试点成功通过了。
改进建议
CargoSorter.sortCargo()直接修改了LoadManifest内部的cargos列表排序后货物顺序变为按重量降序。如果后续需要按原始录入顺序输出或追溯,顺序已被破坏且不可恢复。我认为可以在CargoSorter中加一个新方法,不改变原来列表,返回一个新的列表
第二次作业
目标
设计一个扩展的航班货运配载模块,实现以下功能:
- 航班信息管理:记录航班号、最大起飞重量、最大业载重量。
- 货舱管理:
每个货舱有唯一标识(如“前舱”)、最大载重、行数、列数(组成位置网格)。
货舱与其位置是组合关系(CargoCompartment 创建时内部生成 Position 列表)。
货舱与装载的货物是聚合关系(Cargo 可独立存在)。 - 货物装载:
输入所有待装载货物(名称、重量、目标货舱ID)。
系统先按货物重量从高到低排序,再依次尝试将货物装入指定的货舱。
如果目标货舱的当前重量 + 该货物重量 ≤ 该货舱最大载重,则装载成功,否则装载失败并给出提示。 - 输出要求:
按排序后的顺序输出每件货物的装载结果(成功或失败)。
输出每个货舱的已装载总重量及状态(是否超载)。
输出航班整体总重量及与最大起飞重量、最大业载重量的对比,判断整体是否超载。
设计与分析
货舱有唯一标识、最大载重、行数列数(位置网格),且货舱与位置是组合关系(货舱创建时内部生成Position列表)。货物必须指定目标货舱ID,装载时先按重量降序排序,再依次尝试装入对应货舱,并校验货舱容量。因此新增Position、CargoCopartment、LoadDispatcher和InputValidator。其中LoadDispatcher负责排序、查找货物和装载逻辑,与Flight形成依赖关系。
算法
排序算法:TimSort
查找算法:线性查找(Linear Search)
实现方法
对货物按重量降序排序后,根据每个货物的目标货舱ID尝试装载,并实时校验各货舱及航班的重量限制,最后输出配载状态。
代码规模
第二次作业代码规模如下表
| Source File | Total Lines | Source Code Lines | Source Code Lines [%] | Comment Lines | Comment Lines [%] | Blank Lines | Blank Lines [%] |
|---|---|---|---|---|---|---|---|
| Main.java | 73 | 67 | 91.8% | 0 | 0% | 6 | 8.2% |
| Position.java | 14 | 11 | 78.6% | 1 | 7.1% | 2 | 14.3% |
| Cargo.java | 22 | 19 | 86.4% | 1 | 4.5% | 2 | 9.1% |
| CargoCopartment.java | 42 | 36 | 85.7% | 2 | 4.8% | 4 | 9.5% |
| Flight.java | 59 | 51 | 86.4% | 1 | 1.7% | 7 | 11.9% |
| LoadDispatcher.java | 29 | 26 | 89.7% | 1 | 3.4% | 2 | 6.9% |
| InputValidator.java | 9 | 8 | 88.9% | 1 | 11.1% | 0 | 0% |
| Total: | 248 | 218 | 87.9% | 7 | 2.8% | 23 | 9.3% |
类图
- Main主类(程序入口,输入输出)
- Position货舱位置类(表示货舱中的行、列位置)
- Cargo货物类
- CargoCopartment货舱类(管理位置网格、货物列表、当前重量及装载)
- Flight航班类
- LoadDispatcher调度类(货物排序、查找货物、装载货物到指定货舱)
- InputValidator输入校验类(整数/浮点数的范围校验)

时序图

复杂度分析
第二次作业的复杂度分析如下表
| 类名 | 总方法数 | 圈复杂度(总和) | 最大方法圈复杂度 | 平均方法圈复杂度 | 最大嵌套深度 | 源代码行数 |
|---|---|---|---|---|---|---|
| Main | 1 | 7 | 7 | 7.0 | 2 | 67 |
| Position | 2 | 2 | 1 | 1.0 | 1 | 11 |
| Cargo | 4 | 4 | 1 | 1.0 | 1 | 19 |
| CargoCopartment | 5 | 6 | 2 | 1.2 | 1 | 36 |
| Flight | 6 | 12 | 5 | 2.0 | 2 | 51 |
| LoadDispatcher | 3 | 7 | 3 | 2.3 | 2 | 26 |
| InputValidator | 2 | 2 | 1 | 1.0 | 1 | 8 |
| 总计/平均 | 23 | 40 | 7 | 1.74 | 2 | 218 |
Main类的main方法复杂度较高,因为它包含了多个循环和条件判断(3个循环 + 3个分支),本质上是在主类中直接编写了完整的业务逻辑
采坑心得
货物在装载时并未与对应的货舱匹配,全部装入一个货舱。重新检查代码发现,代码运行时,对应货舱ID不匹配时,并未切换货舱,导致货物全部填入前舱。
改进建议
Position 类仅提供 getPosName(),无占用标记,也就是只提供了行和列,代码却没用到行和列。并且只考虑了货物的重量,没有考虑货架容量和货物数量。
第三次作业
目标
在第二次作业(多货舱货物装载)基础上,新增旅客管理、载重平衡计算功能。系统需计算飞机总重量、总力矩、实际重心及MAC百分比,并判断重心是否在安全范围内;同时要求手写冒泡排序替代内置排序,增加输入校验,非法输入立即终止程序。最终输出旅客清单、货舱装载明细、重心计算结果及安全判定。
设计与分析
第三次作业在第二次基础上新增旅客管理和载重平衡计算,先提取出预设常量(空机重量/力臂、旅客力臂、前后货舱力臂、MAC参数、安全范围),并明确计算步骤:旅客总重及力矩、货舱总重及力矩、全机总重及总力矩、重心、MAC百分比,最后安全评估。设计上增加Passenger(与Luggage组合,行李在构造器内部new)、WeightBalanceCalculator(静态工具类,无Flight成员变量,所有计算通过参数传入Flight对象)。排序算法被强制要求手写冒泡排序,因此LoadDispatcher的sortCargos方法改为双重循环实现。输入校验类InputValidator需提供统一的整数/浮点数范围校验,非法输入立即退出。
算法
冒泡排序
实现方法
先按货舱ID(1前舱/2后舱)把货物分别装到对应货舱的指定位置,然后对每个货舱内的位置列表用手写冒泡排序按货物重量降序排列,再通过配平计算类遍历乘客和货舱,累加总重量和总力矩,算出重心百分比,最后输出配平评估结果。
代码规模
第三次作业代码规模如下表
| Source File (Class) | Total Lines | Source Code Lines | Source Code Lines [%] | Comment Lines | Comment Lines [%] | Blank Lines | Blank Lines [%] |
|---|---|---|---|---|---|---|---|
| Flight.java | 28 | 26 | 92.9% | 1 | 3.6% | 1 | 3.6% |
| CargoCopartment.java | 55 | 48 | 87.3% | 0 | 0% | 7 | 12.7% |
| Position.java | 27 | 21 | 77.8% | 1 | 3.7% | 5 | 18.5% |
| Passenger.java | 21 | 17 | 81.0% | 1 | 4.8% | 3 | 14.3% |
| Luggage.java | 11 | 9 | 81.8% | 0 | 0% | 2 | 18.2% |
| Cargo.java | 16 | 13 | 81.3% | 0 | 0% | 3 | 18.8% |
| WeightBanlanceCalculator.java | 62 | 55 | 88.7% | 0 | 0% | 7 | 11.3% |
| LoadDispatcher.java | 25 | 23 | 92.0% | 1 | 4.0% | 1 | 4.0% |
| InputValidator.java | 33 | 29 | 87.9% | 1 | 3.0% | 3 | 9.1% |
| Main.java | 92 | 76 | 82.6% | 0 | 0% | 16 | 17.4% |
| Total (所有类) | 370 | 317 | 85.7% | 5 | 1.4% | 48 | 13.0% |
类图
- Flight航班类
- CargoCopartment货舱类
- Position货架位置类
- Cargo货物类
- Passenger旅客类
- Luggage行李类
- WeightBanlanceCalculator配平计算器(静态工具类)
- LoadDispatcher调度类,提供冒泡排序方法
- InputValidator输入校验类(静态工具类)
- Main主类,程序入口

时序图

复杂度分析
第三次作业的复杂度分析如下表
| 类名 | 总方法数 | 圈复杂度(总和) | 最大方法圈复杂度 | 平均方法圈复杂度 | 最大嵌套深度 | 源代码行数 |
|---|---|---|---|---|---|---|
| Flight | 7 | 7 | 1 | 1.0 | 1 | 26 |
| CargoCopartment | 6 | 12 | 5 | 2.0 | 2 | 48 |
| Position | 6 | 6 | 1 | 1.0 | 1 | 21 |
| Cargo | 2 | 2 | 1 | 1.0 | 1 | 13 |
| Passenger | 3 | 3 | 1 | 1.0 | 1 | 17 |
| Luggage | 2 | 2 | 1 | 1.0 | 1 | 9 |
| WeightBanlanceCalculator | 6 | 11 | 2 | 1.83 | 1 | 55 |
| LoadDispatcher | 2 | 7 | 5 | 3.5 | 3 | 23 |
| InputValidator | 4 | 9 | 3 | 2.25 | 1 | 29 |
| Main | 2 | 19 | 18 | 9.5 | 3 | 76 |
| 总计/平均 | 40 | 78 | 18 | 1.95 | 3 | 317 |
Main.main 方法包含多个循环、条件判断和输出,圈复杂度约18。
LoadDispatcher.sortPositionsByCargoWeight 包含双重循环和条件交换,圈复杂度约5。
CargoCopartment.addCargoToPosition 包含两个分支和循环,圈复杂度约5。
InputValidator.getIntInRange 和 getDoubleInRange 各有约3。
采坑心得
输入数据非法,容量不足,评估危险测试等测试点不通过,猜测可能是输出格式出了问题
改进建议
虽然在CargoCopartment中,有addPosition方法添加位置网格,addCargoToPosition方法根据传入的行、列查找对应位置。但是没有考虑货物数量和网格数量,会出现货物数量超过网格数量的情况。
综合性总结
收获
本次迭代作业,每次作业都在前一次的基础上增加新需求,使我对需求与代码的联系的理解大大加深了。最开始我习惯把所有业务逻辑全部塞在Main中,现在会把不同的逻辑放在不同的类中,做到职责清晰。三次作业都有不同的限制,让我更加灵活运用代码。随着InputValidator类的加入,让我逐步掌握会非法数据的处理,并且考虑可能会出现的各种情况。本次作业集会让我对类图的绘制更加熟练。
不足
对算法的运用不熟练,靠基础堆上去,越到后面代码的复杂度越来越高

浙公网安备 33010602011771号