一、前言
该三次作业围绕航班货运配载这一统一业务背景展开,是对同一问题从基础到复杂、从简单到完善的不断精细化迭代过程,整体难度循序渐进、逐步递增,形成了一套完整的编程实践训练体系。
作业重点考察Java面向对象编程的核心知识点,首先是类的设计与使用,以及类与类之间各类关联关系的理解与实践,包括依赖、聚合、组合等核心关系。例如在Flight航班类中,需要包含货舱类、乘客类等多个关联类的对象,通过合理的类结构设计,实现不同实体之间的逻辑关联与数据交互,这也是面向对象编程中高内聚、低耦合思想的具体体现。
其次是数据封装特性的实际应用。题目中要求将每个类的数据成员设置为私有可见,保证数据的安全性与封装性,但业务逻辑又需要在其他类中访问和修改这些私有数据,这就要求熟练掌握getter和setter方法的编写与调用,通过访问器方法实现不同类之间的数据传递,真正理解封装特性的设计意义。
同时,作业也深入考察了静态方法与非静态方法的区别及使用场景。像InputValidator数据校验类、LoadDispatcher数据处理类,这类工具类的方法无需依赖类的实例对象,目的是提供通用的功能调用,因此必须将其定义为静态方法,从而可以直接通过类名调用,无需重复实例化,极大简化了代码结构,提升了程序的复用性。
此外,数组与集合的灵活运用也是本次作业的核心考点。题目中所有货物数据都需要通过容器进行存储、遍历、排序和管理,若仅使用基础一维数组,不仅代码繁琐,还存在长度固定、操作不便的问题;而ArrayList作为常用的动态集合,自带丰富的增删改查方法,能够大幅简化代码逻辑,降低开发难度,熟练掌握集合的使用,是高效完成本次作业的关键。
整体来看,本次三次作业的题量设置合理,再加上课程给出的完成时间较为充裕,只要投入足够的时间梳理逻辑、调试代码,完全可以顺利完成。更重要的是,三次作业关联性极强,后续题目都是在前序作业的基础上进行功能拓展与细节完善,只要吃透前一次作业的设计思路与代码逻辑,后续只需要在原有代码框架上进行修改和补充,相比全新的独立题目,不仅代码量更少,整体逻辑也更加连贯清晰,能帮助我们循序渐进地巩固面向对象编程的知识体系。
二、设计与分析
第一次作业
作业要求
设计一个基础的航班货运配载模块。系统需要记录航班的基本信息(航班号、最大起飞重量、最大业载重量)。地勤人员可以按照货物重量从高到低向该航班添加货物(货物名称、重量)。系统需要实时计算当前已装载的总重量,并判断是否超载。
实现方式
使用ArrayList动态集合来存储所有货物数据,将其作为Flight航班类的成员属性,以此实现货物数据与航班信息的绑定管理。之后通过Cargo货物类封装货物的名称、重量等基础信息,再借助CargoSorter排序工具类完成货物按重量降序的逻辑处理,最终完成数据的调用、业务逻辑处理以及结果输出。
代码规模
第一次代码规模如下

代码分析:从代码质量检测指标来看,本次作业的代码整体质量表现优秀,所有类的圈复杂度均处于合理区间,其中最大圈复杂度仅为5(CargoSorter排序类),无高复杂度、高风险的代码模块,程序逻辑清晰、可读性强,后续维护难度低。Main主类的代码拆分做得十分到位,仅23行有效代码,逻辑干净简洁,没有出现业务代码堆砌的问题,严格遵循了主类仅负责流程调度、不实现复杂业务逻辑的设计原则。Cargo、Flight、LoadManifest等实体类与工具类的代码语句数量分布均衡,方法拆分粒度合理,每个方法都聚焦单一功能,符合单一职责的设计思想。但同时代码也存在明显的优化空间:一是整体注释率普遍偏低,仅Flight类注释率达到12.1%,其余类几乎没有编写注释,后续开发中若长时间未接触代码,容易出现逻辑遗忘、维护困难的问题;二是CargoSorter排序类的分支占比达到25%,排序逻辑中的条件分支较多,后续可以进一步简化排序逻辑、减少冗余分支,进一步降低代码复杂度。
类图
第一次代码类图如下:

类图分析:第一次作业的类图结构比较简单,整体只设计了五个类,分别是Flight航班类、Cargo货物类、CargoSorter货物排序类、LoadManifest配载清单类和Main主类。Cargo类主要用来存放货物的名称和重量,同时提供获取和修改这些信息的方法,把货物的基础信息都封装在这个类里。Flight类是整个程序的核心,里面用集合存了多个货物对象,相当于一个航班管理所有货物,还能获取航班号、最大载重等信息。CargoSorter专门负责货物的排序,只做排序这一件事;LoadManifest用来计算所有货物的总重量,并且展示装载情况;Main主类就是程序的入口,把所有类串联起来运行。
编写过程
最初我采用基础一维数组存储货物数据,但数组长度固定,增删、传参操作繁琐,代码逻辑复杂。后来改用ArrayList集合,它作为动态数组,长度可自动变化,自带丰富的增删查改方法,无论是数据调用还是参数传递都便捷许多,大幅简化了代码编写。
在编写包含ArrayList成员的类时,我常忘记在构造方法中实例化集合对象,导致程序运行时出现空指针异常。经过多次调试,我总结出技巧:可以在定义ArrayList变量时直接完成实例化,无需在构造方法中重复初始化,从根源上避免空指针问题,提升代码稳定性。
在实现货物按重量降序排序功能时,我起初使用冒泡排序,但多次调试后,排序测试点始终无法全部通过。经过排查分析,我更换了排序算法,将冒泡排序改为选择排序,调整排序逻辑后,最终顺利通过所有测试用例,也体会到不同排序算法在实际场景中的适配差异。
第二次作业
作业要求
设计一个扩展的航班货运配载模块,实现以下功能:
航班信息管理:记录航班号、最大起飞重量、最大业载重量。
- 货舱管理:
每个货舱有唯一标识(如“前舱”)、最大载重、行数、列数(组成位置网格)。
货舱与其位置是组合关系(CargoCompartment 创建时内部生成 Position 列表)。
货舱与装载的货物是聚合关系(Cargo 可独立存在)。 - 货物装载:
输入所有待装载货物(名称、重量、目标货舱ID)。
系统先按货物重量从高到低排序,再依次尝试将货物装入指定的货舱。
如果目标货舱的当前重量 + 该货物重量 ≤ 该货舱最大载重,则装载成功,否则装载失败并给出提示。 - 输出要求:
按排序后的顺序输出每件货物的装载结果(成功或失败)。
输出每个货舱的已装载总重量及状态(是否超载)。
输出航班整体总重量及与最大起飞重量、最大业载重量的对比,判断整体是否超载。
实现方式
在Flight航班类中新增 ArrayList<CargoCompartment>货舱集合,用来统一管理航班内的所有货舱;同时在CargoCompartment货舱类中定义了 ArrayList<Cargo>货物集合,用来存放当前货舱装载的全部货物。通过这样的层级嵌套结构,就可以通过Flight类的对象逐层调用,对所有货舱及内部货物的数据进行统一管理与操作。
另外创建LoadDispatcher调度工具类,在其中封装了货物装载调度、重量降序排序、货物查找等通用方法,供其他类直接调用;同时在InputValidator数据校验类中,实现了货物重量、货舱载重、航班载重等合法性校验方法,方便多处复用。
代码规模
第二次代码规模如下:

代码分析:整体代码复杂度控制表现良好,绝大多数类的最大圈复杂度均≤5,仅Main类为5、InputValidator类为4,都处于优秀区间;Cargo、Position等实体类圈复杂度为1,仅做纯数据封装,职责划分清晰。整体分支占比偏低,仅LoadDispatcher工具类分支占比达37.5%,属于可接受范围。方法拆分较为合理,平均单方法语句数最高仅33行(为主程序入口,属正常情况),其余业务类方法均短小精炼,没有出现臃肿问题。但代码仍存在不足:多数文件注释率低于3%,几乎无注释,不利于后续阅读与维护;Main类包含37行语句,承担了较多逻辑,后续可拆分出独立工具类,进一步优化代码结构。
类图
第二次类图如下:

类图分析:第二次作业的类图在第一次的基础上做了很多细化,新增了货舱类CargoCompartment和货位类Position,整体结构更丰富了。Flight航班类不再直接管理货物,而是管理多个货舱,每个货舱再管理自己的货物,这样就可以区分前舱、后舱,单独计算每个货舱的重量和超重情况。CargoCompartment货舱类里既有货物集合,也有货位集合,货位和货舱是绑定在一起的,货舱创建了货位才存在,货物可以单独存在,只被货舱装载。LoadDispatcher工具类整合了货物排序、查找、装载调度的功能,替代了之前分散的工具类,使用起来更方便。每个类都写了对应的获取、设置方法,保证数据不会被随意修改,同时能在其他类里正常使用。整体设计更贴近真实的航空配载场景,层次分明,能更细致地处理货物装载的细节问题。
编写过程
由于本次作业是第一次作业的细化升级,因此第一次作业的基础功能在本次仍需完整实现,同时要在此之上拓展新的业务逻辑。我在CargoCompartment货舱类中,新增了 ArrayList<Position>位置集合与 ArrayList<CargoCompartment>货舱集合,将货舱划分为前舱与后舱,分别对应数组下标0和1。在装载货物时,需要指定目标货舱,并且要分别独立计算前舱、后舱的装载重量,单独判断每个货舱是否超重。
同时,我在InputValidator数据校验类中,补充了专门针对CargoCompartment货舱的超重判断方法,按照题目格式要求完成对应信息的输出。在货物排序环节,起初使用选择排序无法满足题目要求,经过调试后,我更换为冒泡排序算法,调整排序逻辑后才顺利通过测试,保证了货物能按重量从高到低正确排序。
第三次作业
作业要求
在前两次题目的基础上,由于在航空器配载中,所有装载项(旅客、前舱货物、后舱货物)都有其对应的力臂。重量乘以力臂等于力矩。所有力矩之和除以总重量,即为飞机的实际重心。为了统一标准,实际重心需要换算为占平均空气动力弦(MAC)的百分比。
实现方式
在前两次作业的基础上,新增四个功能独立的类来完善程序。其中Passenger类负责管理旅客姓名等基本信息,并计算旅客自身的总重量;Luggage类专门用于记录行李的相关重量数据;WeightBalanceCalculator类作为核心计算类,能够依据航空配载的力学公式,精准计算出航班的总重量、总力矩、飞机重心以及重心占平均空气动力弦的百分比;最后对InputValidator类进行了完善,提供统一的静态方法,用于规范获取整数、浮点数等输入数据。
代码规模
第三次作业代码规模如下:

代码分析:相比前两次作业,本次新增了Luggage、Passenger、WeightBalanceCalculator等类,进一步细化了功能模块,单一职责原则落实得更好,代码结构更加清晰。基础实体类设计十分精简,Cargo.java仅8行、Position.java仅4行,完全遵循POJO规范,只负责封装数据,不包含冗余逻辑。工具类的复杂度控制也十分优秀,InputValidator、LoadDispatcher的最大圈复杂度均为0,没有复杂的条件分支,逻辑简洁易维护。但本次作业存在明显缺陷,Main.java存在严重臃肿问题:代码行数达121行,有效语句99行,平均每个方法包含95行代码,单方法代码量过大;同时最大圈复杂度高达19,远超10的安全阈值,属于高风险代码,极易出现逻辑漏洞,调试和后续维护难度极大。
类图
第三次作业类图如下:

类图分析:第三次作业的类图是内容最全面的,在前两次的基础上新增了乘客类Passenger、行李类Luggage、重心计算类WeightBalanceCalculator,还完善了数据校验类InputValidator。Flight航班类不仅管理货舱和货物,还新增了乘客集合,用来管理航班上的所有乘客;Passenger乘客类包含行李类,每个乘客都自带行李,还能计算自身和行李的总重量。WeightBalanceCalculator类专门负责计算总重量、总力矩、飞机重心等专业数据,把复杂的计算单独放在一个类里,逻辑更清楚。InputValidator类可以校验输入的数据是否合法,比如判断数字是不是负数、有没有超出范围,避免程序出错。整体涵盖了货物、乘客、行李、重心计算等全部内容,类的数量更多,分工也更细,各种类之间的关系运用得较为全面。
编写过程
在完成本次第三次作业时,我先暂时搁置货物排序的细节,参照前两次作业的开发流程,先搭建出整个程序的基础代码框架,保证整体结构和类之间的关联关系先搭建完整。随后,我在Flight航班类中新增了 ArrayList<Passenger>乘客集合成员,同时补充了用于计算乘客总重量、行李总重量的相关方法;在Passenger乘客类内部,设计了Luggage行李类作为成员属性,并编写对应的乘客总重量计算方法,以此实现乘客、行李与航班之间的数据关联。
接着,我单独创建了WeightBalanceCalculator重心计算类,专门负责根据题目给定的航空配载公式,完成总重量、总力矩、飞机重心以及重心占平均空气动力弦百分比的计算,将复杂的数学计算逻辑单独封装,保证功能解耦。最后,在第二次作业InputValidator数据校验类的基础上进行拓展,新增了更加全面的数据合法性判断逻辑,专门校验输入数据是否为负数、是否超出题目给定的合理范围,一旦检测到非法数据,就及时给出对应的错误提示,进一步提升程序的健壮性和容错能力。
三、踩坑和心得
1. 刚开始编写代码时,我尝试用一维数组来存储和管理货物数据,但一维数组长度固定,下标操作繁琐,还容易出现越界问题,使用起来很不灵活。后来换成ArrayList动态集合后,增删、遍历、传参都更加便捷高效,这让我意识到,在需要使用数组存储数据的场景中,优先选用ArrayList替代普通数组,能极大简化代码逻辑,提升开发效率。
2. 当排序逻辑反复调试仍无法通过,且自身检查代码语法、逻辑均无错误时,可以尝试更换排序算法。不同排序算法的复杂度、适配场景存在差异,题目往往对排序稳定性、效率有隐性要求,换一种算法往往能解决问题,也让我认识到算法选择需要结合实际场景灵活变通。
3. 若将ArrayList作为类的成员变量,最好在定义时就直接完成实例化。如果放在构造方法中初始化,很容易因疏忽遗漏,导致运行时触发空指针异常。提前实例化能从根源规避这类问题,保证代码稳定性,是编写集合相关代码时很实用的小技巧。
4. 遇到测试用例始终无法通过的情况,除了检查核心逻辑,更要重点关注边界值。边界条件往往存在特殊情况,很容易被忽略,比如第三次作业中数值最小值为1而非0,这类细节问题是程序能否通过测试的关键,处理好边界情况能显著提升代码的完整性。
5. 编写代码时心态尤为重要,急躁和烦躁会严重影响思考效率,很容易陷入逻辑死胡同。遇到难题时要沉下心来,分步梳理逻辑、耐心调试,保持平稳的心态,循序渐进解决问题,相信自己一定能顺利完成。
四、改进和建议
第一题没有对数据进行校验,如果输入负数程序不会提示,与实际情况不符合。
第二题对排序使用的算法未直接说明,我觉得可以稍做提示,避免因为算法使用不一样就不正确,不过这样可以锻炼大家的耐心,也有一点好处吧。
第三题的Position包括前两次作业的都没使用到,我觉得可以让位置和货物关联起来,即每个物品都有它自己的位置,可以通过位置查找货物。
五、总结
本次三次作业围绕航班货运配载问题逐步迭代、难度递增,重点考察了Java面向对象编程核心知识,包括类的设计、类间关联关系、封装特性、静态方法使用以及集合与算法的应用。
作业从基础货物装载,逐步拓展到货舱分区管理、飞机重心配平计算,实现了功能的精细化升级。设计中运用了依赖、聚合、组合等类间关系,通过getter/setter完成数据封装,利用静态工具类实现数据校验与调度处理;同时借助ArrayList简化数组操作,根据需求灵活调整排序算法,解决了货物排序、超重判断、重心换算等核心问题。
编写过程中也遇到诸多问题,从最初使用一维数组的繁琐,到改用ArrayList简化逻辑;从排序算法适配错误,到边界值考虑不周,都在调试中积累了经验,认识到提前实例化集合、重视边界测试的重要性,也锻炼了耐心与问题排查能力。
三次作业也暴露出不足:首次作业缺少数据校验,输入非法数据无法提示;部分题目对算法要求未做明确指引;Position位置类未与货物装载结合使用。后续可补充数据校验逻辑、优化题目指引、完善位置与货物的关联设计,进一步贴合实际业务场景。
整体而言,三次作业完整锻炼了面向对象设计、代码调试与问题优化能力,循序渐进的模式也帮助我扎实掌握了相关编程知识点。我觉得这种循序渐进的方法还是很好的。
浙公网安备 33010602011771号