作业总结1

Java航空器配载系统开发总结报告

一、前言

本阶段完成了航空器配载系统的三次迭代开发,从基础的货物管理到多货舱划分,最终实现了完整的载重平衡计算功能。这是一个典型的渐进式课程设计,每次作业都在前一次基础上增加新的业务需求和设计约束,迫使开发者不断重构和优化代码结构。

三次作业的知识点覆盖了面向对象设计的核心概念、数据结构的合理选择、排序算法的正确实现、物理公式的编程转化以及全面的异常处理机制。难度呈明显的阶梯式上升:第一次作业主要考察基础语法和简单逻辑判断,适合初学者上手;第二次引入多货舱管理和货物分配策略,开始体现系统设计的复杂度;第三次最为综合,涉及旅客实体管理、物理力矩计算、重心百分比换算以及严格的配平安全评估,是对前两次作业的全面升华。

代码量方面,第一次作业约200行,类数量4个;第二次作业扩展到350行左右,类数量7个;第三次作业达到550行以上,类数量11个。题量设计合理,每次作业都能在合理时间内完成,但第三次作业由于涉及多个新增类和对前两次代码的重构,工作量明显增加。难度循序渐进的设计方式值得肯定,既能建立信心,又能不断挑战。

二、设计与分析

2.1 第一次作业设计分析

D5926285293AC6C8F7735E3FECA21949

微信图片_20260518181249_34_2

由上面的类图可以看出,Fight和cargoCompartment和Passenger,同时严格遵守单一职责,数据也具有封装性,保证了数据的安全,实现的都是较为基础的功能,只有货物排序,较为简单。

第一次作业采用了较为基础的四类结构设计。Main类作为程序入口,负责流程控制和输入输出;Flight类管理航班的基本信息,包括航班号、最大载重量和货物数量;Cargo类封装货物实体的名称和重量属性;LoadManifest类承担配载计算的核心逻辑,包括总重量计算和状态判断;CargoSorter类作为独立的排序工具,提供静态排序方法。

这种设计初步体现了职责分离的思想,每个类都有相对明确的职能边界。LoadManifest将配载逻辑与实体类分离,CargoSorter将排序算法独立出来,为后续扩展奠定了基础。

然而,第一次作业存在明显的设计缺陷。首先是输入处理的问题,代码中混用了Scanner的next()和nextLine()方法,导致读取字符串时经常出现空值异常。这是因为nextLine()会读取前一个nextInt()或nextDouble()留下的换行符,需要额外的nextLine()来消耗掉这个换行符,初学者极易在此处出错。

其次是验证逻辑的缺失。代码中没有对负数输入进行校验,也没有对货物数量与实际输入条数的一致性进行验证。如果用户输入负数重量或超过最大载重量的数值,程序仍会继续运行并输出错误结果。

排序算法的选择也存在问题。题目明确要求使用冒泡排序,但实际实现的是选择排序。选择排序每次从未排序部分选出最大元素放到已排序部分末尾,而冒泡排序是通过相邻元素的不断交换将最大元素“冒泡”到末尾。虽然两者时间复杂度相同,但实现方式和题目要求不符。

输出格式方面,第一次作业的输出的与题目示例存在偏差,缺少必要的格式化对齐和单位标注,这在后续作业中得到了改进。

2.2 第二次作业设计分析

428091C646EBA244F1D04E69A75534F4

微信图片_20260518181251_36_2

较第一次作业增加了前后舱的区别,且需要排序功能,生成相应的货物清单,且需要在超重的时候做出相应的警告,难度增加,各类之间紧密相关。

第二次作业在第一次的基础上进行了重要重构和功能扩充。新增的CargoCompartment类负责管理单个货舱的全部信息,包括货舱编号、最大载重量、货架位置和已装载货物列表。Position类的引入将行号和列号封装为独立的对象,体现了面向对象设计中对数据聚合的追求。LoadDisatcher类承担货物调度职责,负责对货物按重量排序并将货物分配到对应货舱。InputValidator类开始建立统一的输入验证体系。

第二次作业的设计亮点体现在多个方面。货舱容量动态检测机制的实现使得每个货舱能够实时跟踪当前载重量,并在超载时给出明确的警告信息,格式为“剩余容量不足(当前载重X/最大载重Ykg)”。货物按重量降序排序后再进行分配,这种策略符合实际业务中优先处理重大件货物的习惯。

多货舱独立管理的设计使得系统具有良好的扩展性。每个货舱都有自己的货物列表、当前重量和最大容量,货舱之间互不干扰。如果需要增加第三个货舱,只需要在Flight中增加对应的属性即可,核心逻辑无需大幅修改。

然而,第二次作业仍有不足。货舱内部使用固定大小的Cargo数组(容量100),而非ArrayList集合,这种设计存在容量瓶颈,且增加了代码的复杂度,需要手动维护CargoCount计数器。排序算法虽然实现了按重量降序排列,但未严格按题目要求使用冒泡排序,仍然沿用第一次作业的选择排序思路。

验证体系虽然初步建立,但不够全面。InputValidator中的isPositive方法只检查大于0,这意味着输入0时会被判定为非法,但实际上货架行号、列号可以为0,货物重量也可以为0。正确的做法应该是使用isNonNegative方法,允许零值输入。此外,货物件数的范围校验也未在第二次作业中实现。

旅客管理功能在第二次作业中完全没有涉及,这为第三次作业的大幅修改埋下了伏笔。

2.3 第三次作业设计分析

0C54B6A9F1D9B56C962BBB35E63D7582

微信图片_20260518181250_35_2

第三次作业是前两次作业的全面升级和整合,实现了完整的航空器配载系统,Main类作为程序入口,协调各组件完成数据读取、业务计算和结果输出。Flight类管理航班基本信息和旅客列表,并持有两个CargoCompartment对象(前舱和后舱)。Passenger与Luggage采用严格的组合关系,旅客登机必带行李,行李对象在Passenger构造器内部通过new关键字创建,不对外暴露修改行李的接口。Cargo类记录货物编号和重量,CargoCompartment类管理货舱内的货物列表和当前载重量。WeightBalanceCalculator作为纯计算工具类,仅提供静态方法进行力矩和重心计算,不持有任何业务对象的成员变量。LoadDisatcher负责货物排序,InputValidator统一处理所有输入验证。

第三次作业的设计亮点值得深入分析。

组合关系的严格实现是本次作业的重要设计约束。Passenger类内部直接new出Luggage对象,外部无法单独修改行李重量,必须通过Passenger的构造方法传入行李重量。这种设计体现了面向对象封装原则,确保旅客和行李的生命周期一致。

纯计算工具类的设计确保了WeightBalanceCalculator没有Flight类型的成员变量。类内部定义了空机重量40000千克、空机力臂16.25米、旅客力臂18米、前货舱力臂12米、后货舱力臂22米、MAC长度5米、MAC前缘距基准15米等静态常量,以及安全范围下限25%和上限38%。所有计算方法都将Flight对象作为参数传入,这种依赖关系而非关联关系的设计使得计算器可以独立测试和复用。

力矩计算公式严格按照物理原理实现。旅客总重量为各旅客标准体重75千克与行李重量之和,旅客总力矩为旅客总重量乘以旅客力臂18米。货舱总力矩为前货舱重量乘以前货舱力臂12米加上后货舱重量乘以后货舱力臂22米。全机总重量为空机重量加旅客总重量加前后货舱货物重量之和,全机总力矩为空机重量乘空机力臂加旅客总力矩加前后货舱力矩之和。实际重心位置为总力矩除以总重量,重心百分比为实际重心减去MAC前缘距离15米除以MAC长度5米再乘以100%。

输入验证体系在第三次作业中得到全面强化。所有数值输入都经过InputValidator的非负校验,遇到负数立即输出“数值不能为负数”并停止程序运行。前舱货物件数需要校验是否在0到总货物件数之间,超出范围时输出“输入必须在最小值到最大值之间”并退出。货舱容量超限检测封装在addCargo方法内部,每次添加货物前检查当前重量加新货物重量是否超过最大容量,超过时输出警告信息并终止装载。

冒泡排序的正确实现终于在第三次作业中得到落实。LoadDisatcher中的sortByw方法使用双层循环,外层循环控制排序轮数,内层循环进行相邻元素的两两比较,当前一个货物的重量小于后一个货物时交换位置,实现降序排列。这种实现完全符合题目要求的冒泡排序算法。

三、采坑心得

坑1:输入处理的换行符问题。 第一次作业中混用next()和nextLine()导致航班号读取为空。根本原因是nextLine()会读取前一个nextInt()或nextDouble()留下的换行符。解决方案是统一使用next()方法读取所有字符串,避免混用。如果必须使用nextLine(),则需要在每次nextInt()后增加一个nextLine()来消耗换行符。

坑2:负数校验遗漏导致程序接受非法输入。 第二次作业中,InputValidator的isPositive方法只检查数值是否大于0,这意味着输入0或负数时不会被正确拦截。正确的做法是区分场景:重量和最大载重量应该允许0,但不应允许负数;货架行号列号也允许0。因此需要设计isNegative方法专门检测负数,而不对上限做限制。

坑3:货舱容量超限检测的位置不当。 第三次作业初版中,容量检测代码写在Main类中,针对前舱和后舱分别判断,导致代码重复且难以维护。改进方案是将容量检测封装到CargoCompartment的addCargo方法内部,货舱自己负责检查容量是否充足,不足时抛出异常并由Main捕获处理。

坑4:重心百分比计算单位混淆。 题目要求安全范围为25%到38%,但代码中错误地使用0.25和0.38进行比较,这是因为WeightBalanceCalculator的Percentage方法返回的是实际比值而非百分比。修正方案是在Percentage方法内部乘以100返回百分比值,或者将安全范围常量定义为25.0和38.0进行比较。

坑5:旅客行李重量未累加。 计算旅客总重量时只加了标准体重75千克,遗漏了行李重量。这暴露了在代码审查时对业务规则检查不仔细的问题。修正后正确累加75.0加getLuggage().getWeight()。

坑6:冒泡排序实现错误。 第一次和第二次作业中错误地实现了选择排序而非冒泡排序。选择排序每轮找出最大元素放到前面,而冒泡排序通过相邻交换逐步将最大元素移动到末尾。两者的区别需要从算法原理层面理解,不能仅凭记忆写代码。

坑7:浮点数精度问题。 多次浮点运算后,实际重心计算结果与预期存在微小偏差。例如总力矩754290.0除以总重量45305.0得到16.647,四舍五入保留一位小数应为16.6,但直接计算可能得到16.7。解决方案是在最终输出时使用String.format进行舍入,或在计算过程中使用BigDecimal。

四、改进建议

使用集合框架替代固定数组。 当前CargoCompartment内部使用容量为100的固定数组,存在容量瓶颈且需要手动维护计数器。改用ArrayList后可以实现动态扩容,代码也更简洁。getCargoCount()可以直接调用list.size(),addCargo直接调用list.add(),无需手动维护索引。

分离控制台输入和业务逻辑。 Main类目前承担了输入读取、数据验证、业务计算和输出显示四大职责,代码行数超过150行,违反了单一职责原则。建议引入InputHandler类专门负责读取和初步验证,OutputHandler类专门负责格式化输出,Main仅保留流程协调功能。

加强异常处理机制。 当前遇到错误直接调用System.exit(1)退出程序,这种方式过于粗暴且不利于单元测试。建议定义NegativeValueException、OverloadException、RangeException等自定义异常类,让Main类的调用者决定如何处理异常。

优化计算精度。 浮点数计算存在精度误差,关键的量如力矩、重心位置应使用BigDecimal。WeightBalanceCalculator中的乘除运算需要指定舍入模式和小数位数,例如divide方法需要传入RoundingMode.HALF_UP。

增加配置文件支持。 空机重量40000千克、力臂16.25米等参数当前硬编码在WeightBalanceCalculator中。建议将这些参数抽取到aircraft.properties配置文件中,使用Properties类动态加载,提高系统的可配置性。

完善文档和注释。 当前代码几乎没有注释,类和方法的作用只能靠命名猜测。建议增加Javadoc注释,每个类说明其职责,每个方法说明参数含义和返回值,关键算法说明实现思路。

五、总结

通过三次计算工具类静态方法的设计模式。在业务理解方面,深入了解了航空配载的业务逻辑和力矩平衡原理,掌握了重心百分比的计算方法和安全范围的判定规则。在代码规范方面,认识到统一输入验证的必要性,养成了异常处理的良好习惯。

后续需要深入学习设计模式,包括工厂模式创建实体对象、策略模式实现排序算法、观察者模式监听重量变化。测试技术方面需要掌握JUnit单元测试和边界值测试方法。高级Java特性方面需要学习泛型、枚举和Lambda表达式。

课程的三次迭代设计能够清晰看到代码的成长轨迹,从简单到复杂的渐进式任务设计值得肯定。建议增加代码审查环节,让同学互评代码质量;增加设计模式讲解,帮助解决实际问题;引入Git版本控制,培养团队协作意识。

三次作业让我从编写面条式代码的初学者,成长为能够思考类结构、关注代码质量的开发者,是宝贵的编程实践经历。

posted @ 2026-05-18 22:27  皓白x  阅读(10)  评论(0)    收藏  举报