第二次Blog作业
PTA题目集8-9的Blog总结:
面对对象(java)课程的第二单元结束了,在分别对两次题目集中的“航空货运管理系统”题目的提交源码进行分析后,我收获颇丰:
熟悉了 Java 在实际场景应用中的语法;
进一步巩固了面向对象的设计理念;
深刻体会到了程序设计中逻辑完整性的重要;
掌握了基于实际场景的测试方法。
个人观点:
个人认为本次作业主要在于正则表达式的学习以及ArrayList或ListLink的使用,在于对队列的增删改,题目的复杂更偏向于对问题的思考方法。
Complexity Metrics(复杂度分析)
方法的复杂度分析主要基于循环复杂度(v (G)),它可理解为穷尽程序流程每一条路径所需要的试验次数。Essentail Complexity(ev (G))表示一个方法的结构化程度,范围在 [1, v (G)] 之间,值越大程序结构越 “病态”。Design Complexity(iv (G))表示一个方法和它所调用的其他方法的紧密程度,范围也在 [1, v (G)] 之间,值越大联系越紧密。对于类,有 OCavg(类的方法的平均循环复杂度)和 WMC(类的总循环复杂度)两个项目。
下面我将从程序结构、测试情况以及 bug 分析几个方面来总结电梯调度相关的题目。
第一次作业(航空货物订单管理系统)
作业要求
航空快递以速度快、安全性高成为急件或贵重物品的首选。本题目要求对航空货运管理系统进行类设计,具体说明参看说明文件。
输入格式:
按如下顺序分别输入客户信息、货物信息、航班信息以及订单信息。
客户编号
客户姓名
客户电话
客户地址
运送货物数量
[货物编号
货物名称
货物宽度
货物长度
货物高度
货物重量
]//[]内的内容输入次数取决于“运送货物数量”,输入不包含“[]”
航班号
航班起飞机场
航班降落机场
航班日期(格式为YYYY-MM-DD)
航班最大载重量
订单编号
订单日期(格式为YYYY-MM-DD)
发件人地址
发件人姓名
发件人电话
收件人地址
收件人姓名
收件人电话
输出格式:
如果订单中货物重量超过航班剩余载重量,程序输出The flight with flight number:航班号 has exceeded its load capacity and cannot carry the order. 程序终止运行。
如果航班载重量可以承接该订单,输出如下:
客户:姓名(电话)订单信息如下:
航班号:
订单号:
订单日期:
发件人姓名:
发件人电话:
发件人地址:
收件人姓名:
收件人电话:
收件人地址:
订单总重量(kg):
微信支付金额:
货物明细如下:
明细编号 货物名称 计费重量 计费费率 应交运费
1 ...
2 ...
注:输出中实型数均保留1位小数。
类图

系统整体设计思路
这个程序实现了一个简单的航空货物订单管理系统,主要功能包括:
• 读取用户输入的客户信息、货物信息、航班信息和订单信息
• 计算订单总重量和总费用
• 检查订单是否超出航班载重限制
• 格式化输出订单详情
核心类设计与职责
- 客户类 (Customer)
• 功能:存储客户基本信息
• 关键属性:客户 ID、姓名、电话、地址
• 设计特点:简单的数据封装类,提供基本的 getter/setter 方法 - 货物类 (Good)
• 功能:计算货物的计费重量和费用
• 核心逻辑:
o 实际重量与体积重量取较大值作为计费重量
o 根据计费重量分档计算费用:
<20kg: 35元/kg
20-50kg: 30元/kg
50-100kg: 25元/kg
=>100kg: 15元/kg
- 航班类 (Flight)
• 功能:存储航班基本信息和载重限制
• 关键属性:航班号、出发 / 到达机场、日期、最大载重
• 设计特点:简单的数据封装类,提供基本的 getter/setter 方法 - 订单类 (Order)
• 功能:整合客户、货物、航班信息,计算订单总重量和费用,输出订单详情
• 核心方法:
o totalWeight():计算所有货物的总重量
o totalFare():计算订单总费用
o print():格式化输出订单详情
• 设计特点:
o 聚合了多个领域对象(Customer、Flight、Good [])
o 负责业务逻辑的整合与输出展示
输入处理与数据流程 - 输入读取:
o 使用 Scanner 按顺序读取客户、货物、航班、订单信息
o 对输入数据进行简单的类型转换和验证(如整数转换) - 对象构建:
o 依次创建 Customer、Good []、Flight 对象
o 将上述对象作为参数构建 Order 对象 - 业务处理:
o 调用 Order 的totalWeight()方法计算总重量
o 检查总重量是否超过航班载重限制
o 若未超过,调用 Order 的print()方法输出订单详情
代码规模

复杂度分析





改进方法:
- 输入处理:统一用nextLine()读取输入并转换类型,避免换行符问题;添加数据合法性验证(如重量非负、数字格式)。
- 抽象与多态:将Good改为抽象类,定义getRate()等抽象方法,通过NormalGood等子类实现不同货物的费率计算逻辑,消除getRate()中传递自身实例的冗余设计。
- 客户与订单优化:为Customer添加折扣属性,区分个人 / 企业客户;Order中用ArrayList替代数组存储货物,支持动态扩展,并将支付方式设为参数实现灵活输出。
- 代码规范与复用:提取计费标准等硬编码值为类常量,使用更具描述性的变量名(如departureAirport替代Airport1);利用 Java Stream 简化集合遍历逻辑(如计算总重量、总费用)。
封装与健壮性:确保所有类属性私有,通过公共方法访问;添加异常处理机制,提升程序容错能力。
Bug 分析
公测
暂时没有问题。
互测
在互测中,程序没有出现导致程序崩溃的错误,但存在一些逻辑不够完善的地方。
测试方法
通过PTA上的测试案例以及老师的补充案例来测试程序的正确性。同时,对程序输出结果进行详细记录和分析,观察电梯运行过程是否符合预期。
第二次作业(航空货物订单管理系统迭代)
作业要求:
在第一题的基础上进行迭代
类图:

实现方法:
关键改动点
- 客户类型与折扣机制
• 新增客户类型:区分 “个人(Individual)” 和 “企业”,分别对应 9 折和 8 折优惠。
• Customer类重构:新增customerType和discount属性,通过构造方法初始化折扣率。 - 货物分类与多态设计
• 抽象类Good:定义公共属性(ID、名称、尺寸、重量)和抽象方法(getRate()、calculateFare())。
• 子类实现:
o NormalGood(普通货物)、ExpediteGood(加急货物)、DangerousGood(危险货物)继承Good,重写费率计算逻辑。
o 不同货物类型根据计费重量分档计算费率(如加急货物费率高于普通货物)。 - 订单逻辑扩展
• 总费用计算:在订单总费用中应用客户折扣(totalFare() = 货物总费用 × 折扣)。
• 支付方式适配:支持 “微信”“支付宝”“现金” 及自定义支付方式,输出时自动转换为中文名称。 - 输入处理优化
• 解决换行符问题:在读取数值后添加scanner.nextLine(),避免nextLine()读取空值。
• 类型驱动创建对象:根据输入的货物类型(goodType),通过switch-case创建对应子类实例。
代码规模

复杂度分析








改进方法:
- 代码规范:简化客户类型判断逻辑,统一变量命名(如goodList→cargoList),利用Math.max简化计费重量计算。
- 健壮性:添加输入校验(如货物尺寸 / 重量非负、机场代码格式),处理无效货物类型和支付方式,避免空指针和非法数据。
- 设计优化:引入支付方式枚举类,解耦支付逻辑;用ArrayList替代数组,支持动态扩展;通过策略模式封装折扣策略,提升扩展性。
- 异常处理:使用try-with-resources自动关闭输入流,在主类中捕获并处理业务异常,增强程序容错能力。
- 扩展性:为航班添加机场代码校验,通过接口抽象折扣策略,便于未来新增客户类型或折扣规则。
Bug 分析
公测
当我输入数据完时,出现了报错。读取int类型后直接调用nextLine(),导致获取到空字符串。原因:nextInt()等数值方法不会消耗输入流中的换行符(\n),nextLine()会直接读取该换行符作为输入。解决方法:在每次读取数值后,手动调用一次scanner.nextLine()消耗剩余换行符。
互测
在互测中出现了性能问题。虽然程序能够正确处理请求,但在处理大量请求时,处理速度较慢。这是由于在请求处理算法中存在一些低效的操作,例如在遍历请求队列时没有采用更高效的数据结构和算法。
测试方法
通过PTA上的测试案例以及老师的补充案例来测试程序的正确性。同时,自己也通过手动输入案例对程序输出结果进行详细记录和分析,观察帮空货物订单系统运行过程是否符合预期。
关于设计模式的思考
在本次 Java 课程第二单元中,设计模式的应用是我逐渐领悟到的关键要点。起初,我专注于实现基本的功能,并未对设计模式给予足够的重视。随着作业的不断迭代,代码的复杂度和维护难度逐渐增加,我深刻体会到了合理运用设计模式的重要性。。
在后续的学习和实践中,我将更加注重设计模式的学习和应用。我会深入研究各种设计模式的原理和适用场景,在编写代码之前,先思考是否可以应用合适的设计模式来优化代码结构。通过不断地实践和总结,提升自己运用设计模式解决实际问题的能力,从而编写出更加高质量的代码。
踩坑心得
封装优先:将数据和行为封装在类内部,避免跨类直接访问属性(如通过customer.getDiscount()而非暴露discount字段)。
依赖抽象而非实现:通过抽象类和接口定义规范,子类实现细节(如Good抽象类定义接口,子类实现费率计算)。
测试驱动思维:在编写代码前考虑边界情况(如重量为 0、支付方式非法),避免逻辑漏洞。
逐步迭代验证:分模块测试客户、货物、订单逻辑,确保每个类的功能独立正确,再整合测试整体流程。
这些 “坑” 本质上是对面向对象设计原则理解不深的体现。通过本次作业,我深刻认识到:代码的优雅性源于对细节的把控和对设计原则的坚守,后续需加强对设计模式的学习,在实践中不断提升系统设计能力。

浙公网安备 33010602011771号