第二次blog作业

前言:
学习本次航空管理作业感受:
这次迭代作业相较于之前电梯简单了很多,再请教同学之后,也是顺利写下来了。java的类设计以及继承多态方面的细节处理很多,从最初简单实现客户、货物、航班等类的基础功能,到迭代后加入客户类型、货物类型和支付方式等复杂逻辑,每一次代码的优化都让我对类的封装、继承和多态有了更直观的理解。尤其是运费策略接口和不同策略类的设计,不仅解决了复杂计费问题,还让我掌握了策略模式的实际应用。在调试过程中,处理订单重量与航班载重量的逻辑判断、格式化输出等细节时遇到不少困难,但在同学的帮助下也是将问题一个一个地解决了。相信在下次写这种内容较多的题目时,我能将代码结构设计的更完整符合逻辑,细节处理更好。

设计与分析
第一次大作业
7-3 NCHU_航空货运管理系统(类设计)
分数 60
中等
作者 段喜龙
单位 南昌航空大学
航空快递以速度快、安全性高成为急件或贵重物品的首选。本题目要求对航空货运管理系统进行类设计,具体说明参看说明文件。
OO第九周作业题目说明.pdf

输入格式:
按如下顺序分别输入客户信息、货物信息、航班信息以及订单信息。

客户编号
客户姓名
客户电话
客户地址
运送货物数量
[货物编号
货物名称
货物宽度
货物长度
货物高度
货物重量
]//[]内的内容输入次数取决于“运送货物数量”,输入不包含“[]”
航班号
航班起飞机场
航班降落机场
航班日期(格式为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位小数。

输入样例:
在这里给出一组输入。例如:

10001
郭靖
13807911234
南昌航空大学
2
101
发电机
80
60
40
80
102
信号发生器
55
70
60
45
MU1234
昌北国际机场
大兴国际机场
2025-04-22
1000
900001
2025-04-22
南昌大学
洪七公
18907912325
北京大学
黄药师
13607912546
输出样例:
在这里给出相应的输出。例如:

客户:郭靖(13807911234)订单信息如下:

航班号:MU1234
订单号:900001
订单日期:2025-04-22
发件人姓名:洪七公
发件人电话:18907912325
发件人地址:南昌大学
收件人姓名:黄药师
收件人电话:13607912546
收件人地址:北京大学
订单总重量(kg):125.0
微信支付金额:3350.0

货物明细如下:

明细编号 货物名称 计费重量 计费费率 应交运费
1 发电机 80.0 25.0 2000.0
2 信号发生器 45.0 30.0 1350.0






第二次大作业
7-3 NCHU_航空货运管理系统(继承与多态)
分数 50
较难
作者 段喜龙
单位 南昌航空大学
航空快递以速度快、安全性高成为急件或贵重物品的首选。本题目要求对航空货运管理系统进行类设计,具体说明参看说明文件。
OO第十二周作业题目说明.pdf

输入格式:
按如下顺序分别输入客户信息、货物信息、航班信息以及订单信息。

客户类型[可输入项:Individual/Corporate]
客户编号
客户姓名
客户电话
客户地址
货物类型[可输入项:Normal/Expedite/Dangerous]
运送货物数量
[货物编号
货物名称
货物宽度
货物长度
货物高度
货物重量
]//[]内的内容输入次数取决于“运送货物数量”,输入不包含“[]”
航班号
航班起飞机场
航班降落机场
航班日期(格式为YYYY-MM-DD)
航班最大载重量
订单编号
订单日期(格式为YYYY-MM-DD)
发件人地址
发件人姓名
发件人电话
收件人地址
收件人姓名
收件人电话
支付方式[可输入项:Wechat/ALiPay/Cash]
输出格式:
如果订单中货物重量超过航班剩余载重量,程序输出The flight with flight number:航班号 has exceeded its load capacity and cannot carry the order. ,程序终止运行。
如果航班载重量可以承接该订单,输出如下:
客户:姓名(电话)订单信息如下:

航班号:
订单号:
订单日期:
发件人姓名:
发件人电话:
发件人地址:
收件人姓名:
收件人电话:
收件人地址:
订单总重量(kg):
[微信/支付宝/现金]支付金额:

货物明细如下:

明细编号 货物名称 计费重量 计费费率 应交运费
1 ...
2 ...
注:输出中实型数均保留1位小数。

输入样例:
在这里给出一组输入。例如:

Corporate
10001
郭靖
13807911234
南昌航空大学
Expedite
2
101
发电机
80
60
40
80
102
信号发生器
55
70
60
45
MU1234
昌北国际机场
大兴国际机场
2025-04-22
1000
900001
2025-04-22
南昌大学
洪七公
18907912325
北京大学
黄药师
13607912546
ALiPay
输出样例:
在这里给出相应的输出。例如:

客户:郭靖(13807911234)订单信息如下:

航班号:MU1234
订单号:900001
订单日期:2025-04-22
发件人姓名:洪七公
发件人电话:18907912325
发件人地址:南昌大学
收件人姓名:黄药师
收件人电话:13607912546
收件人地址:北京大学
订单总重量(kg):125.0
支付宝支付金额:4360.0

货物明细如下:

明细编号 货物名称 计费重量 计费费率 应交运费
1 发电机 80.0 40.0 3200.0
2 信号发生器 45.0 50.0 2250.0





踩坑心得
第一次大作业
在第一次大作业中,我订单类只创建了一个类,但老师后续在群里提醒之后,我创建了两个类,一个是订单类,另一个是订单明细类,这样设计比较合理,代码更加优质。

第二次大作业
代码还是写少了,经常构造参数顺序与调用顺序不一致,导致编译错误时还半天找不到错误。然后支付方式枚举值与输入不匹配引发输出错误,输入为"wechat"(小写),但枚举值为"Wechat"(大写),但我没注意到,就弹出IllegalArgumentException: wechat。写到后面脑子发昏了,误将货物类型作为客户类型判断折扣,
这里的cargoType应改为customerType。然后还有一个我从c语言时候就很容易犯得错误,索引错误,这题中OrderItem明细编号未从 1 开始
i应改成i+1。

改进建议
现有问题:
题目集 9 的Order.printInvoice方法中,货物明细编号通过OrderItem的构造参数传入(i + 1),若订单项中途删除,编号会出现断层。
改进建议:
在Order类中维护订单项列表的索引,使用List.indexOf(item) + 1动态生成编号
或引入OrderItem的自增 ID 生成机制,确保编号连续性3. 异常处理的缺失(现有代码优化点)
现有不足:
代码中未处理货物尺寸为负数、重量为 0 等非法输入,直接通过Scanner解析可能导致NumberFormatException。
改进方案:
在Cargo构造方法中增加参数校验:

在main方法中增加全局异常捕获,提示用户重新输入。
现有不足:
Order和Cargo类中重复使用DecimalFormat("0.0")进行格式化,可提取为公共工具类。
改进方案:
新增NumberFormatter工具类:

现有不足:
当前仅通过手动输入测试,未覆盖边界条件(如货物体积重量等于实际重量、客户折扣临界点),易遗漏逻辑漏洞。
改进建议:
使用 JUnit 测试Cargo类核心方法:

现有不足:
题目集 9 中,当货物数量庞大时(如 10 万件),orderItems.stream().mapToDouble()流式计算会产生较高内存开销,且串行处理效率较低。
改进方案:
改用并行流或传统循环:

总结
一、核心收获:面向对象编程的基础认知与实践
通过这两次航空货运管理系统的作业,我对 Java 面向对象编程(OOP)有了从理论到实践的完整认知。最初接触题目集 8 时,我还习惯用面向过程的思维堆砌代码,将客户信息、货物计算、订单处理全部写在Main类中,导致代码冗长且难以维护。但随着题目迭代(题目集 9 新增客户类型、货物类型、支付方式等复杂逻辑),我被迫尝试用 OOP 的思维重构代码,逐步理解了以下核心概念:

  1. 类与对象:数据与行为的封装
    在题目集 8 中,我学会将客户、货物、航班等实体抽象为独立类(如Customer、Cargo、Flight),每个类封装其属性(如货物的长宽高、航班的最大载重量)和方法(如货物计算体积重量、航班校验载重)。例如,Cargo类通过构造方法初始化货物参数,并封装getVolumetricWeight()和calculateFreight()等方法,避免了数据暴露在外的安全隐患。这种封装让代码结构更清晰,后续修改某个类的逻辑时(如调整运费计算规则),只需聚焦该类内部,无需全局搜索代码。
  2. 接口与策略模式:解耦业务逻辑
    题目集 9 引入多种货物类型(普通 / 加急 / 危险)后,我通过FreightStrategy接口和三个实现类(NormalFreightStrategy等)实现了运费策略的多态。这是我首次真正理解 “策略模式” 的应用场景:不同货物类型的计费规则可以独立变化,而Cargo类只需依赖接口,无需关心具体策略实现。例如,当加急货物的费率从 “40 元 /kg” 调整为 “45 元 /kg” 时,只需修改ExpediteFreightStrategy类,其他代码无需变动。这种设计让系统扩展性大幅提升,也让我体会到 “面向接口编程” 的优势。
  3. 枚举类型:规范业务数据输入
    题目集 9 要求处理客户类型(Individual/Corporate)、货物类型(Normal/Expedite/Dangerous)等固定选项,我通过枚举类型(enum)定义这些选项,避免了字符串硬编码的风险。例如,使用CargoType.valueOf(input)转换输入时,编译器会强制检查合法值,若输入错误类型(如 “expedite” 小写),程序会抛出明确异常,而非静默错误。这让我意识到枚举在保证数据合法性和代码可读性上的重要性。
    二、实践中的问题与自我反思
    虽然完成了两次作业,但过程中暴露了许多初学者的典型问题,这些问题反映了我在基础语法、逻辑严谨性和系统设计意识上的不足。
  4. 基础语法与细节处理漏洞
    输入流操作不熟练:在读取用户输入时,多次因忽略换行符(nextLine()与next()的区别)导致数据错位。例如,题目集 8 中读取完整数(如货物数量)后,未用scanner.nextLine()消费剩余换行符,直接读取字符串时获取空值,导致程序崩溃。
    参数校验缺失:初期代码未对货物尺寸、重量、航班载重量等进行非负数校验(如允许宽度为 - 50cm),直到测试时发现逻辑错误(体积重量为负数)才补全校验逻辑。这让我明白,防御性编程应从构造方法开始,避免非法数据流入系统。
    浮点数精度问题:直接使用double累加运费金额,未考虑精度丢失(如0.1 + 0.2不等于0.3)。虽然题目允许保留 1 位小数,但这一问题在金融场景中可能引发严重后果,后续需学习BigDecimal的规范使用。
  5. 面向对象设计的浅层应用
    类职责单一性不足:Order类同时承担订单逻辑(载重校验、运费计算)和发票输出(printInvoice),违反单一职责原则。例如,当题目要求修改输出格式(如将 “微信支付” 改为 “微信付款”)时,需要修改Order类代码,而实际上输出逻辑应独立封装。
    策略模式的不彻底性:题目集 9 中客户类型折扣(企业 8 折、个人 9 折)仍通过if-else硬编码在Order类中,未抽象为DiscountStrategy接口。这导致新增客户类型(如 VIP 客户 7 折)时需修改Order类,违背开闭原则。这说明我对策略模式的理解仍停留在 “货物类型” 层面,未意识到业务规则的可扩展性。
  6. 异常处理与代码鲁棒性薄弱
    未捕获运行时异常:枚举转换(如CargoType.valueOf(input))和数值解析(如Double.parseDouble)时未使用try-catch,导致用户输入非法值时程序直接崩溃,缺乏友好提示。例如,输入货物类型为 “invalid” 时,程序抛出IllegalArgumentException并终止,而非提示 “请输入合法货物类型”。
    边界条件测试不足:未主动测试临界值(如货物重量恰好等于体积重量、航班载重量刚好等于订单总重量),直到提交后发现样例输出中 “订单总重量” 需保留 1 位小数(如 125.0kg),才意识到格式化字符串的重要性(DecimalFormat("0.0"))。
    三、下一阶段学习规划:夯实基础与拓展能力
  7. 巩固基础:语法细节与工具类应用
    深入理解输入输出机制:熟练掌握Scanner的next()/nextLine()区别,学会用hasNext()预判输入,避免因输入顺序错误导致的逻辑漏洞。
    规范数值处理:学习BigDecimal的精确计算方法,应用于运费、折扣等涉及货币的场景,避免浮点数精度问题。
    封装公共工具类:将重复使用的代码(如数值格式化、枚举转换)提取为工具类(如NumberFormatter、EnumUtils),提高代码复用性。
  8. 深化面向对象设计:设计模式与原则
    学习更多设计模式:在策略模式基础上,尝试工厂模式(如CargoFactory根据类型创建货物实例)、单例模式(如全局的FlightManager),减少main方法中的new操作,降低对象创建的耦合度。
    严格遵循设计原则:用 “单一职责原则” 拆分Order类的业务逻辑与输出逻辑,用 “开闭原则” 抽象客户折扣策略,确保新增功能时不修改现有代码。
    练习类图设计:在编码前通过类图(UML)规划类结构、接口和依赖关系,避免编码过程中频繁重构。
  9. 提升代码健壮性:测试与异常处理
    引入单元测试:学习 Junit 框架,为核心类(如Cargo、Flight)编写测试用例,覆盖边界条件(如体积重量等于实际重量、客户折扣临界点)和异常场景(如非法枚举值、负数输入)。
    完善异常处理体系:定义自定义异常类(如InvalidInputException、FlightOverloadException),在关键方法中抛出明确异常,并用try-catch统一处理,向用户提供友好的错误提示。
  10. 拓展实践:从控制台到复杂场景
    模拟真实业务场景:假设题目集新增 “多订单分配至同一航班” 功能,尝试在Flight类中维护已承载重量,实现多订单累计载重校验,提升系统的业务复杂度。
    学习文件操作:将客户、航班信息存储到文本文件(如 JSON/CSV),实现数据持久化,突破控制台程序的局限性。
    四、再次总结:初学者的成长感悟
    这两次作业对我来说是从 “写代码” 到 “设计代码” 的转折点。初期面对复杂需求时,我常因缺乏整体设计思路而焦虑,但通过逐步拆分问题(先定义类,再实现接口,最后整合逻辑),逐渐掌握了 OOP 的思维方式。虽然代码仍有诸多不足(如设计模式应用不彻底、异常处理简单),但每一次调试和重构都让我更清晰地理解:优秀的代码不是一次性写成的,而是通过不断迭代和优化进化而来。
    作为 Java 初学者,我深刻认识到基础的重要性 —— 无论是语法细节(如this关键字、枚举用法)还是设计原则(如单一职责),都需要通过大量实践加深理解。未来,我会更注重代码的 “可维护性” 和 “可读性”,避免为了实现功能而牺牲架构质量,努力向 “优雅的面向对象设计” 靠近。
posted @ 2025-05-19 13:12  xuan324  阅读(44)  评论(0)    收藏  举报