题目集8-9航空货运管理系统

一、前言

题目集 8-9 以航空货运管理系统为核心场景,聚焦空运费计算、订单处理及业务逻辑实现,要求在完成功能开发的同时严格遵循面向对象设计原则(单一职责、里氏代换、开闭原则、合成复用等)。题量覆盖输入输出处理、业务规则计算、类结构设计等多模块,难度体现在代码架构的合理性与可扩展性上,需平衡功能实现与设计原则的双重要求。

二、设计与分析

(一)SourceMonitor 报表分析

第一次提交(优化前代码)


(1)代码规模:
Main.java行数 318 行,语句数 130 条,定义 7 个类(含接口),平均每个类 6.29 个方法。
特点:类数量较少,功能集中于核心业务类(如Goods、Order),但职责边界模糊,如Goods类同时承担数据封装与运费计算逻辑。

(2)复杂度指标:
最高复杂度方法为Goods.getRate()(复杂度 8),逻辑集中于分段费率判断,分支深度 2 层,平均复杂度 1.20。

(3)核心问题:
主方法耦合:Main.main()承担 “上帝角色”,违背单一职责原则。
注释缺失:注释仅占 1.4%,关键逻辑(如折扣计算、货物类型判断)缺乏文档。
职责碎片化:Order类同时处理订单创建与运费计算,违背合成复用原则。

第二次提交(优化后代码)


(1)代码规模:
行数增至 629 行,语句数 320 条,类数扩展至 15 个,平均每个类 5.73 个方法。
特点:引入继承体系(如Customer子类、Goods子类),类间依赖复杂化,但职责划分更细。

(2)复杂度指标:
最高复杂度方法为Main.main()(复杂度 9),包含输入解析、业务调度、输出控制,分支占比 10.9%,逻辑嵌套深度达 5 层。

(3)核心问题:
单一职责违背:Goods类混合数据属性与业务逻辑(如计费重量计算、费率判断)。
硬编码缺陷:客户类型、支付方式、费率规则直接写入代码,扩展成本高。
可读性不足:无注释,关键逻辑(如体积重量计算)缺乏说明。

(二)类图分析(结合代码实现)

第一次提交类图


核心缺陷:
(1)客户与货物类型固化:客户、货物类型仅单一类,折扣与费率硬编码在Order类中,违背开闭原则。
(2)方法的职责不明:方法过少导致一个方法可能有多个职责。

第二次提交类图


改进点:
(1)多态与继承:
Customer抽象类派生出Individual(9 折)和Corporate(8 折),通过getDiscount()实现多态。
Goods抽象类派生出NormalGoods/ExpediteGoods/DangerousGoods,重写getRate()实现差异化费率策略。
(2)策略模式应用:
支付方式抽象为Payment接口,新增Cash支付时只需实现接口,符合开闭原则。
(3)职责分离:
GoodsOrder类封装货物集合操作(总重量、总价格计算),Order类专注订单流程管理。

对比总结 维度 扩展性 职责清晰度 代码复杂度
第一次提交 低(硬编码客户 / 货物类型) 模糊(混合数据与逻辑) 单一职责、开闭原则不足 低(类少但功能集中)
第二次提交 高(通过继承 / 接口扩展) 较清晰(细分GoodsOrder等) 多态、依赖倒转原则实现较好 中(类多但层次化)

三、采坑心得

(一)功能实现误区

  1. 计费重量计算逻辑错误
    (1)问题描述:体积重量计算正确(widthlengthheight/6000),但比较时误将体积重量作为默认值,且方法名拼写错误(tureWeight应为trueWeight)。
    (2)复现案例:实际重量 80kg,体积重量 96kg 时,错误取 80kg 作为计费重量。
    (3)解决方案:修正方法名getBillableWeight(),明确职责;添加单元测试覆盖边界值(重量 = 体积重量、重量 > 体积重量)。
    (4)优化效果:计费逻辑准确性提升,代码可读性增强,后续扩展新计费规则更便捷。

  2. 航班载重校验逻辑位置错误
    (1)问题描述:主程序直接通过goodsOrder.getTotalWeight() > flight.getMaxWeight()判断载重,业务逻辑分散在main方法中,违背单一职责。
    (2)解决方案:在Flight类中添加canCarry(GoodsOrder goodsOrder)方法封装。

(二)设计原则违背案例

  1. 单一职责原则违反(Main类)
    问题表现:
    Main.main()承担输入解析、业务调度、输出格式化等多项职责,代码行数超 300 行,复杂度 9。
    重构方案:
    拆分出InputHandler(输入解析)、OrderService(业务逻辑)、OutputFormatter(输出控制)类,实现职责分离。
    优化效果:Main类复杂度降低,各模块独立维护,如输入格式变更时仅需修改InputHandler。
  2. 里氏代换原则违反(Corporate客户类)
    问题表现:
    Corporate类重写getDiscount()返回固定 0.8,但未约束父类Customer的契约(如允许返回负数折扣)。
    解决方案:
    在Customer抽象类中明确getDiscount()返回值范围(public abstract double getDiscount();),并添加单元测试验证子类实现。

四、改进建议

(一)代码优化方向

  1. 增强注释与文档
    关键方法注释。
    类定义说明:在Customer类添加注释 “客户抽象类,派生子类实现不同折扣策略”,提升可读性。
  2. 降低方法复杂度
    拆分Main.main():将输入解析逻辑封装为parseCustomer()、parseGoods()等私有方法,每个方法代码量控制在 50 行内。
    策略模式重构费率计算:
    定义RateStrategy接口,各货物类型实现calculateRate()方法,Goods类通过依赖注入使用策略。

(二)设计模式应用

  1. 工厂模式解耦对象创建
    创建CustomerFactory工厂类,通过类型参数返回具体客户实例,避免主程序switch-case硬编码。

  2. 模板方法模式统一流程
    在Order类定义模板方法processOrder(),将通用流程(载重校验、价格计算、输出)封装,子类可重写特定步骤。

五、总结

(一)学习收获

设计原则落地:通过两次迭代,理解单一职责原则对代码可维护性的决定性作用,以及多态与接口在扩展中的核心价值。
业务抽象能力:能够从复杂场景中提炼实体关系(客户 - 货物 - 订单 - 航班),并通过类设计封装属性与行为。
调试思维升级:学会使用边界值分析(如重量 = 0、体积重量 = 实际重量)和错误注入(如非法输入)验证代码健壮性。

(二)待提升领域

设计模式熟练度:策略模式、工厂模式等虽能理解理论,但在编码中仍需参考文档,未能形成条件反射式应用。
代码重构能力:面对复杂继承体系时,缺乏系统性重构方法论,担心修改影响现有功能。
性能优化意识:未关注集合遍历效率、对象创建开销等性能细节,需学习流式处理、缓存等优化手段。

(三)心得

通过两次题目集的实践,深刻体会到面向对象设计 “少即是多” 的哲学 —— 初期牺牲代码量换取合理架构,后期将大幅降低维护成本。未来需继续将设计原则融入日常编码,培养 “可扩展、易维护” 的编程肌肉记忆。

posted @ 2025-05-25 20:36  故中  阅读(20)  评论(0)    收藏  举报