blog

面向对象设计与构造 —— 航空货运配载单元三次作业总结

写在前面

面向对象设计与构造课程第一单元以航空航班货物配载、多货舱管理、载重重心平衡为核心场景,布置了三次迭代式编程作业。从最基础的单航班单货物载重统计,到多货舱货物智能分配装载,再到融合旅客、行李、前后双货舱的航空重心配平系统,三次作业难度层层递进、功能逐步迭代。

通过本单元学习,我熟练掌握了 Java 基础语法与面向对象核心编程思想,建立起类与对象、封装、组合聚合的设计思维;理解了代码可扩展性、高内聚低耦合的工程设计理念;学会使用 SourceMonitor 进行代码复杂度度量、借助类图分析程序结构,同时积累了程序调试、边界测试、错误排查的实战经验。三次作业不仅夯实了编码能力,更让我体会到面向对象思想在实际业务系统开发中的核心价值。

Complexity Metrics(复杂度分析概念)

在进行作业代码分析前,先明确 SourceMonitor 复杂度度量核心指标,用于后续三次作业方法与类的复杂度评估:

  • v (G) 循环复杂度:代表程序所有分支路径的数量,数值越大方法逻辑越繁琐,常规合理值应控制在 10 以内。
  • ev (G) 基本复杂度:衡量程序结构化程度,规避冗余分支与嵌套,值越低代码结构越清晰、无冗余逻辑。
  • iv (G) 设计复杂度:表征当前方法与其他方法的调用耦合程度,数值越高耦合性越强,代码越难维护与拓展。
  • OCavg、WMC:分别为类的平均方法复杂度、类总方法复杂度,用于评估整个类的设计臃肿程度。

第一次作业

作业要求

设计航班与货物基础类,实现货物信息封装、按重量降序冒泡排序、航班总载重计算、最大载重对比及超载状态判断,完成输入解析、数据处理与格式化输出。

实现方式

采用类封装 + 数组存储的基础设计模式。定义Cargo货物类封装货物名称与重量私有属性,提供 getter 方法;Flight航班类维护航班号、最大载重、货物数组与有效货物数量,内置货物添加、冒泡降序排序、总重量累加、超载判断等核心方法;Main主类负责控制台输入、对象实例化、方法调用与结果打印。整体采用顺序式逻辑,依托数组固定长度存储货物,完成基础业务流程。

代码规模

通过 SourceMonitor 统计本次作业代码规模:

表格

Source File

Total Lines

Source Code Lines

Source Code Lines[%]

Comment Lines

Blank Lines

Main.java

42

38

90%

2

2

Cargo.java

36

32

89%

2

2

Flight.java

128

115

90%

6

7

Total

206

185

89%

10

11

整体代码共 206 行,有效代码 185 行,注释与空行占比合理,代码精简无冗余,符合基础面向对象编程规范。

类图设计

本次作业采用基础三层类结构:

  1. Cargo 货物类:私有成员变量 cargoName、cargoWeight;构造方法、属性 getter 方法。
  2. Flight 航班类:私有成员 flightNo、maxWeight、cargoArray 数组、count 计数;提供 addCargo、sortByWeightDesc、getTotalWeight、isOverWeight 等业务方法。
  3. Main 主类:仅包含 main 方法,负责程序入口、输入处理、对象调度与结果输出。

类之间为组合关系,Flight 聚合多个 Cargo 对象,Main 作为调度者调用两大核心类,结构简单清晰,无多余依赖。

复杂度分析

第一次作业核心方法复杂度指标如下:

表格

方法

ev(G)

iv(G)

v(G)

Main.main

1

2

2

Flight.addCargo

1

1

1

Flight.sortByWeightDesc

2

3

5

Flight.getTotalWeight

1

2

2

Flight.isOverWeight

1

1

1

Cargo.getter 方法

1

1

1

平均值

1.15

1.75

2.25

从复杂度数据可以看出,整体方法复杂度极低,仅冒泡排序方法sortByWeightDesc因双层循环与条件判断 v (G) 达到 5,仍在合理范围。所有方法 ev (G) 接近 1,说明代码结构化良好;iv (G) 普遍偏低,类与方法间耦合度小。缺点在于采用固定长度数组存储货物,扩展性差,后续新增货物数量时需修改代码。

Bug 分析

公测问题

公测中无逻辑正确性错误,输出格式基本符合要求,但存在货物排序边界处理不足问题:当货物数量为 0 或 1 时,冒泡排序仍执行循环,虽不影响结果但存在冗余运算。

自测与采坑

  1. 数组越界异常:最初冒泡排序循环边界未设置count-1,遍历数组全部空位导致访问 null 元素报错。
  2. 总重量计算错误:未按有效数量 count 遍历,直接遍历数组长度,累加 null 对象重量引发异常。
  3. 输出格式精度问题:未使用 printf 格式化保留 1 位小数,导致输出结果格式不统一。

测试方法

手动构造测试用例:正常多货物、单货物、零货物、刚好满载、轻微超载 5 类场景,逐行核对排序结果、总重量、超载提示,覆盖基础边界条件。

第二次作业

作业要求

在第一次作业基础上迭代升级,新增多货舱、货舱位置管理、货物指定目标货舱、按重量降序自动配载、装载失败提示、多货舱载重状态独立评估、航班整体载重校验功能,引入集合存储与工具类解耦设计。

实现方式

摒弃固定数组,改用ArrayList 动态集合存储货舱与货物;拆分单一职责类,新增Position位置类管理货舱行列坐标、LoadDispatcher货物调度排序类、InputValidator输入校验工具类;CargoCompartment货舱类独立管理单个货舱的最大载重、当前载重与货物列表;Flight航班类统一管理多个货舱,提供按 ID 查找货舱、统计全航班货物总重方法。采用面向对象分工设计,将排序、输入校验、位置描述等功能剥离为独立工具类,实现高内聚低耦合。

代码规模

本次作业代码规模显著提升,模块拆分更细致:

表格

Source File

Total Lines

Source Code Lines

Source Code Lines[%]

Comment Lines

Blank Lines

Main.java

85

78

92%

3

4

Position.java

32

28

87%

2

2

Cargo.java

40

35

88%

3

2

CargoCompartment.java

76

69

91%

4

3

Flight.java

68

62

91%

3

3

LoadDispatcher.java

28

25

89%

1

2

InputValidator.java

24

21

87%

1

2

Total

353

318

90%

17

18

代码总量增至 353 行,拆分 7 个独立类,每个类仅负责单一功能,代码复用性大幅提升,注释分布均匀,可读性强。

类图设计

本次作业类结构更加模块化,核心关系如下:

  1. 基础实体类:Position(位置属性)、Cargo(货物属性);
  2. 容器类:CargoCompartment包含多个 Cargo 与 Position,Flight聚合多个 CargoCompartment;
  3. 工具类:LoadDispatcher负责货物排序、InputValidator负责数据合法性校验;
  4. 调度入口:Main处理输入、调用工具类完成排序配载、输出各货舱及航班状态。

类之间依赖关系清晰,工具类与实体类解耦,修改排序规则或校验规则无需改动核心业务类,可扩展性明显优于第一次作业。

复杂度分析

第二次作业核心方法复杂度:

表格

方法

ev(G)

iv(G)

v(G)

Main.main

2

4

5

LoadDispatcher.sortCargos

1

2

2

CargoCompartment.addCargo

1

2

3

CargoCompartment.getCurrentWeight

1

1

1

Flight.findCompartmentById

2

3

4

InputValidator 校验方法

1

1

1

平均值

1.38

2.15

2.76

整体复杂度小幅上升,但仍处于合理区间。Flight.findCompartmentById因遍历集合 + 条件判断复杂度稍高,Main.main因输入处理、空行过滤、字符串拆分逻辑分支较多 v (G) 为 5。相较于第一次作业,通过工具类拆分复杂逻辑,避免了单个方法臃肿,设计耦合度依然较低。

Bug 分析

公测问题

公测无逻辑错误,所有配载、载重计算、状态判断均正确,但存在输入兼容不足问题:无法自动处理多行空输入、多空格分隔数据,部分特殊格式输入导致拆分失败。

互测与自测 Bug

  1. 输入读取异常:使用split(" ")无法匹配多个连续空格,导致货物、货舱参数解析错乱。
  2. 空行干扰:复制粘贴输入存在空行,直接读取会抛出数字转换异常。
  3. 货舱载重累加错误:初次设计未封装getCurrentWeight,每次遍历货舱货物重复计算,冗余且易出错。
  4. 货物装载判断失误:未提前校验剩余载重,直接添加货物后再判断,导致无效数据存入集合。

测试方法

采用边界测试 + 格式测试:构造多空格、空行、零货舱、零货物、货舱刚好满载、多货物跨货舱分配等用例;同时模拟错误输入格式,验证程序容错能力。

第三次作业

作业要求

在前两次基础上全面升级为航空完整载重平衡系统,新增旅客与行李管理、前后双独立货舱、货物按 ID 升序排序、航空力矩与重心百分比计算、起飞重量 / 业载双重超载判断、重心安全范围评估、完整载重平衡舱单输出,同时增加全量输入负数合法性校验。

实现方式

采用多层组合 + 静态常量工具类设计。拆分Luggage行李类、Passenger旅客类(内置标准体重、关联行李);CargoCompartment分为前后舱,新增货物 ID 冒泡排序;Flight关联旅客列表与前后双货舱;WeightBalanceCalculator作为静态计算工具类,封装空机重量、力臂、重心安全范围等常量,实现力矩、重心百分比、配平安全评估的核心算法。主类增加全流程输入负数校验,拦截非法数据,整体实现业务逻辑与算法计算完全分离。

代码规模

第三次作业功能最复杂,代码量与类数量达到峰值:

表格

Source File

Total Lines

Source Code Lines

Source Code Lines[%]

Comment Lines

Blank Lines

Main.java

156

142

91%

8

6

Luggage.java

28

24

86%

2

2

Passenger.java

45

40

89%

3

2

Cargo.java

32

29

90%

1

2

CargoCompartment.java

86

79

92%

4

3

Flight.java

72

65

90%

4

3

WeightBalanceCalculator.java

118

107

91%

7

4

Total

543

486

90%

29

28

总代码 543 行,拆分 7 个核心类,涵盖实体、容器、算法计算、调度入口全模块,业务逻辑分层明确,算法与数据完全解耦。

类图设计

本次作业类结构最复杂,完整体现面向对象组合与单一职责:

  1. 基础实体:Luggage(行李重量)、Passenger(旅客 + 组合行李)、Cargo(货物 ID + 重量);
  2. 容器管理:CargoCompartment(前后舱、货物排序、装载校验)、Flight(聚合旅客、前后双货舱);
  3. 算法工具:WeightBalanceCalculator(静态常量、力矩计算、重心评估、舱单打印);
  4. 程序入口:Main(输入校验、对象初始化、货物分配、调用计算方法)。

类之间多层组合嵌套,每个类各司其职,静态工具类无需实例化即可调用,适合固定算法与常量管理,完全符合工程化设计思想。

复杂度分析

第三次作业核心方法复杂度显著提升:

表格

方法

ev(G)

iv(G)

v(G)

Main.main

3

6

8

CargoCompartment.sortCargo

2

3

5

WeightBalanceCalculator.calculate

2

5

7

WeightBalanceCalculator.print

4

8

11

Passenger.getTotalWeight

1

1

1

平均值

2.1

3.8

5.6

本次因重心计算、舱单格式化输出、全量输入校验包含大量分支条件,部分方法 v (G) 接近 10 临界值。print方法因多模块数据打印、格式拼接、状态判断,循环与分支较多,复杂度最高。整体 ev (G) 与 iv (G) 同步上升,主要是业务逻辑复杂化、方法调用层级增多导致,但仍通过类拆分避免了单个方法逻辑过度臃肿。

Bug 分析

公测问题

公测无功能性 Bug,载重计算、重心百分比、安全状态判断均准确,但舱单格式排版不够规整,冗余空格较多,细节优化不足。

自测采坑

  1. 重心公式计算错误:混淆 MAC 前缘、力臂参数,导致重心百分比偏差,安全判断失效。
  2. 负数输入未拦截:初期未校验旅客数、重量、货舱行列负数,出现非法业务数据。
  3. 货物排序错乱:冒泡排序 ID 升序条件写反,货物输出顺序颠倒。
  4. 前后舱货物分配越界:未校验前舱货物数量区间,出现分配数量超出总货物数的逻辑漏洞。
  5. 浮点数精度误差:直接使用 double 累加重量,部分场景出现微小精度偏差。

测试方法

采用全场景覆盖测试:零旅客、零货物、单货舱满载、重心临界值(25%、38%)、超出起飞重量、超出业载重量、负数非法输入等多类测试用例,手动核对力矩、重心百分比、配平状态,确保算法与逻辑双重正确。

采坑心得

纵观三次作业迭代,我在编码与调试过程中遇到的问题具有很强的共性,也积累了详实的实战心得:

边界条件是 Bug 高发区:三次作业均在循环边界、数组 / 集合遍历范围、数值正负、临界载重、极值数据上出现错误。例如冒泡排序循环边界、有效货物数量遍历、重心安全临界值判断,忽略边界极易引发越界、计算错误、逻辑失效。后续编码必须先梳理边界场景,再编写核心逻辑。

输入处理与数据校验不可忽视:从第二次作业多空格、空行解析失败,到第三次作业负数非法输入,让我意识到程序不能依赖输入格式完美,必须主动做trim 去空、多空格拆分、数值范围校验、负数拦截,提升程序健壮性。

面向对象设计拆分至关重要:第一次作业所有逻辑集中在主类与航班类,臃肿难维护;后两次通过工具类拆分、单一职责拆分、算法与数据分离,代码可读性、可维护性大幅提升。若前期类结构设计混乱,后期新增功能会层层嵌套,复杂度飙升。

复杂度控制需提前规划:SourceMonitor 分析显示,复杂 Bug 多集中在 v (G) 过高的方法中,大量 if-else 嵌套、多层循环会让调试难度倍增。学会将复杂方法拆分为多个子方法,降低单个方法分支数量,是减少 Bug 的关键。

测试不能仅依赖样例:官方样例仅覆盖常规场景,大量边界、非法格式、临界值 Bug 需要手动构造测试用例才能发现。三次作业互测与自测经验表明,手动造针对性测试用例比盲目自动化测试更高效。

改进建议

代码结构改进

  1. 引入继承与抽象类:可设计WeightItem抽象父类,封装货物、旅客通用重量属性,减少重复代码;前后货舱可继承统一货舱父类,复用装载、排序方法。
  2. 统一异常处理:摒弃 if 判断拦截错误、直接退出程序的方式,改用try-catch捕获输入格式异常、数值非法异常,自定义异常提示信息,程序更优雅健壮。
  3. 拆分超长方法:第三次作业 main 方法、print 打印方法代码过长,可按功能拆分为输入初始化、货物装载、重心计算、舱单输出多个子方法,降低复杂度。

功能逻辑改进

  1. 优化装载算法:目前货物固定分配前后舱,可改进为自动最优配载,根据货舱剩余重量自动分配货物,最大化利用载重空间。
  2. 增加数据持久化:将航班配载舱单保存至本地文本文件,支持查询历史配载记录,拓展实用性。
  3. 完善输出格式:优化舱单排版,对齐文字与数值,去除冗余空格,模拟真实航空载重平衡单据格式。

代码规范与复杂度改进

  1. 统一命名与注释:规范类、方法、变量命名风格,为核心算法、复杂分支逻辑添加注释,便于后续阅读与修改。
  2. 替换低效排序:手动冒泡排序可替换为Collections.sort工具排序,简化代码同时提升效率。
  3. 常量配置分离:将航空力臂、安全重心范围、空机重量等常量单独放入常量类,统一管理,修改参数无需改动业务代码。

总结

知识与能力收获

经过三次航空货运配载作业迭代,我系统掌握了 Java 面向对象编程核心知识点:熟练运用类与对象、封装、组合聚合、构造方法、getter/setter;掌握数组与 ArrayList 集合的使用场景与差异;学会冒泡排序、累加统计、力矩重心等算法逻辑;能够使用 SourceMonitor 分析代码复杂度、借助类图梳理程序结构;养成了先设计类结构、后编码、重视边界测试的编程习惯。

同时,在工程思维上有明显提升:理解了单一职责、高内聚低耦合的设计原则,懂得模块化拆分代码、解耦业务逻辑与工具算法,不再局限于实现功能,更追求代码的可读性、可扩展性与可维护性。

待提升方向

  1. 继承、多态、接口、设计模式掌握不足,三次作业未用到高级面向对象特性,后续需深入学习工厂模式、策略模式,优化复杂系统设计。
  2. 异常处理、泛型、文件 IO 等进阶知识应用欠缺,代码容错性与拓展性仍有提升空间。
  3. 算法优化能力不足,排序、遍历逻辑仍停留在基础实现,缺乏效率优化思维。

课程与作业改进建议

  1. 作业设计:三次作业迭代式设计非常合理,从基础到综合贴合实际业务,建议继续保持梯度递进模式,增加少量设计模式相关作业场景。
  2. 课堂教学:建议增加 UML 类图绘制、SourceMonitor 复杂度分析实操教学,讲解如何通过类图提前规划代码结构,减少后期重构成本。
  3. 实验与互测:可增加课堂代码互评环节,让同学互相阅读代码、分析设计优劣,借鉴不同编程思路;同时布置专项边界测试练习,培养测试思维。
  4. 作业指导:针对复杂业务算法(如重心计算),可提供原理讲解与公式说明,降低理解难度,更专注于面向对象设计实现。
posted @ 2026-05-17 19:11  ifavorite  阅读(7)  评论(0)    收藏  举报