Java面向对象程序设计——作业集1~3总结Blog

一、前言

面向对象程序设计课程的前三次PTA作业围绕“航空器配载与货运管理系统”这一真实业务场景展开,从这次任务中我充分理解到了:
  1. 类与对象的基本设计
  2. 类间关系(组合,聚合,继承)
  3. 类与类之间的整合
三次作业由基础货运配载模块、多货舱管理模块到航空器配平计算模块逐步演进,严格遵循单一职责原则、封装与高内聚低耦合思想,实现了10个左右的核心类及其协作关系

二、设计与分析

2.1 第一次作业:基础货运配载模块

作业要求:

【本次作业需求说明】
设计一个基础的航班货运配载模块。系统需要记录航班的基本信息(航班号、最大起飞重量、最大业载重量)。地勤人员可以按照货物重量从高到低向该航班添加货物(货物名称、重量)。系统需要实时计算当前已装载的总重量,并判断是否超载。
【设计要求】
类设计必须符合单一职责原则(SRP),参考类图如下所示(仅作参考,可自行加工具类)。
注意:类设计如果违背了SRP,此题不得分。

核心类:

  1. Main
  2. Flight
  3. Cargo
  4. LoadManifest

类间关系:

 

 复杂度分析:

 

心得:第一次作业让我认识到,类设计的首要任务是明确每个类的职责边界。提前规划好“这个类负责什么”是写出可维护代码的基础。哪怕代码量少,如果职责划分混乱,后期修改成本也会成倍增长,本次实践让我初步建立面向对象设计意识:类设计的核心是“职责划分”,每个类只负责一项明确功能,避免“万能类”。

2.2 第二次作业:多货舱管理与重量排序装载

作业要求:

【本次作业需求说明】

设计一个扩展的航班货运配载模块,实现以下功能:

  1. 航班信息管理:记录航班号、最大起飞重量、最大业载重量。
  2. 货舱管理:

每个货舱有唯一标识(如“前舱”)、最大载重、行数、列数(组成位置网格)。

货舱与其位置是组合关系(CargoCompartment 创建时内部生成 Position 列表)。

货舱与装载的货物是聚合关系(Cargo 可独立存在)。

  1. 货物装载:

输入所有待装载货物(名称、重量、目标货舱ID)。

系统先按货物重量从高到低排序,再依次尝试将货物装入指定的货舱。

如果目标货舱的当前重量 + 该货物重量 ≤ 该货舱最大载重,则装载成功,否则装载失败并给出提示。

  1. 输出要求:

按排序后的顺序输出每件货物的装载结果(成功或失败)。

输出每个货舱的已装载总重量及状态(是否超载)。

输出航班整体总重量及与最大起飞重量、最大业载重量的对比,判断整体是否超载。

【设计要求】

必须严格遵循单一职责原则(SRP),不得将多个职责合并到一个类中。违背 SRP 本题不得分。

必须实现以下类(参考提供的类图与代码框架):

Position:表示货舱中的一个位置(行、列),提供 getPosName() 等方法。

Cargo:表示货物,包含 id(货物名称)、weight。

CargoCompartment:货舱类,包含 id、maxWeight、positions(组合)、cargos(聚合),提供 addCargo(Cargo cargo)、getCurrentWeight() 等方法。

Flight:航班类,包含航班号、最大起飞重量、最大业载重量、List。

LoadDispatcher:调度类,负责对货物列表按重量降序排序(sortCargos)、查找货物(FindCargo)。

InputValidator:输入校验类,提供整数、浮点数的范围校验方法。

类间关系:

 

 复杂度分析:

 

 心得:第二次作业让我深刻认识到,类间关系的选择(组合还是聚合、依赖还是关联)是业务语义的准确映射。Position作为货舱的组成部分——是组合;Cargo可以在货舱间转移,独立存在——是聚合。一旦关系选错,设计根基就会动摇。

2.3 第三次作业:航空器配平计算

作业要求:

【设计要求】
本次迭代新增约4个类,系统总类数达到10个左右。严禁使用继承和多态(无extends、无interface、无instanceof),请严格遵循以下关系与单一职责设定,注:原有的 Flight 类需增加List<Passenger> 属性,体现关联关系。原有的 LoadDispatcher(排序)在本次生成报告时需被内部调用。另外,本次作业中的排序算法不允许使用朗姆达表达式及Collections.sort()方法,必须使用循环完成排序过程(算法采用冒泡排序)

类间关系:

 

 复杂度分析:

 

 心得:在这一道题中测试点没有成功全部通过,在这一方面我深刻认识到面向对象的复杂性。并且,在Main类承担了过多流程调度与数据处理职责,违背单一职责原则,导致代码臃肿、可读性差,计算方面倘若数据过多很容易出错,需要在进行更改,考虑更加高效的排序策略。

三、问题

在三次作业的编码与调试过程中,我遭遇了多个典型问题,有些源于设计疏漏,有些暴露在测试边界。

3.1 排序算法的稳定性与实现细节

第一次作业使用Java内置排序工具,实现简单、效率高,无需关注底层逻辑。但第三次作业强制要求手写冒泡排序,禁止使用Lambda与内置排序方法,这一要求暴露了我对基础排序算法细节掌握不扎实的问题。

实现冒泡排序时,我最初错误地将内层循环终止条件写为j < list.size() - i,遗漏了-1,导致最后一轮循环访问了已排序完成的尾部元素。虽然测试数据量较小,未触发运行时错误,但逻辑上存在明显漏洞,属于典型的边界条件错误。

本次教训深刻:算法实现必须逐行验证逻辑,尤其是循环边界、数组下标、终止条件等细节;将排序逻辑封装在独立的LoadDispatcher类中是良好设计,当排序需求变更时,仅需修改该类,不影响其他业务代码,充分体现高内聚低耦合优势。

3.2 正则表达式与语义校验的边界

第二次作业处理输入数据时,我最初尝试用正则表达式统一验证所有数值输入,意图一次性拦截非数字字符串。但正则表达式仅能判断输入格式是否为数字,无法校验数值的业务合法性,例如负数、零值、超出范围的数值。

这一设计导致“-50”这类负数输入绕过格式校验,直接进入业务逻辑层,引发货物重量、货舱载重等关键数据异常,导致后续重量计算、超载判断全部出错。直到测试阶段才发现该漏洞,浪费大量调试时间。

后续解决方案采用“双重校验机制”:第一层用Scanner的hasNextInt()、hasNextDouble()方法判断输入格式合法性,拦截非数字输入;第二层由独立的InputValidator工具类,校验数值是否为非负、是否在指定业务范围内。分层校验彻底堵住漏洞,提升系统可靠性。

3.3边界条件测试不充分

第三次作业测试阶段,第十个测试点始终无法通过,反复排查后发现是边界条件处理不当:当货物重量等于货舱剩余载重、旅客重量为零、重心处于安全临界值时,代码未正确处理“等于”场景,导致判断逻辑错误。

反思发现,我设计测试用例时,仅关注常规场景,未系统性覆盖等价类边界值,尤其是最大值、最小值、零值、临界值等特殊情况。边界条件是程序最易出错的地方,也是测试的核心重点。

本次教训:测试用例设计需遵循“等价类划分+边界值分析”原则,全面覆盖正常、异常、边界场景;对于数值比较、状态判断等逻辑,必须严格区分“大于”“小于”“等于”三种情况,避免逻辑疏漏。

四、总结

回顾这三次作业的迭代历程,我从一个仅掌握Java基础语法的初学者,逐步成长为能够独立设计10余个类协同工作的面向对象编程学习者。具体收获如下:

  1. 深刻理解了面向对象的核心原则。封装、单一职责、类间关系不再是书本概念,而是指导编码的实战准则。每一次需求变更都成为检验设计柔性的试金石,让我切身感受到“高内聚、低耦合”的价值。
  2. 掌握了专业工具辅助开发的能力。PowerDesigner让类间关系一目了然,SourceMonitor将代码质量从“感觉”提升到“数据”。这些工具在后续学习设计模式和大规模系统开发中将持续发挥价值。
  3. 积累了丰富的调试与重构经验。从浮点精度陷阱到排序边界错误,从正则滥用到头文件膨胀,每个坑都深化了对语言特性和工程实践的理解。面对bug时,已能系统性地从数据、逻辑、测试多维度定位根因。

本次实践也暴露了我存在的不足:类间关系建模能力仍需加强,对组合、聚合、依赖等关系的语义理解不够精准;算法基础薄弱,手写代码时细节把控不足;测试用例设计能力欠缺,边界场景覆盖不全面。后续学习中,我将针对性强化这些短板,多做设计练习、夯实算法基础、规范测试流程,进一步提升面向对象设计与开发能力。

总而言之,本次航空器配载与货运管理系统的三次迭代实践,是一次宝贵的成长经历。它不仅提升了我的编程技能,更培养了工程思维、责任意识和严谨态度,为后续专业学习和职业发展奠定坚实基础。

 

posted @ 2026-05-18 20:55  ALKQ  阅读(3)  评论(0)    收藏  举报