一.前言:本次两道题目是编写一段代码以实现航空货运管理系统的一些基础功能,总体上难度不大,要求要体现出面向对象设计原则中的单一职责原则、里氏代换原则、开闭原则以及合成复用原则、依赖倒转原则,其中涉及了以下知识点
(一)继承与多态的应用
(二)对象设计原则中的单一职责原则、里氏代换原则、开闭原则以及合成复用原则、依赖倒转原则
(三)面向对象的设计模式
两次题目依旧是第二次为第一次的迭代,在第一次代码的基础上要求实现更为复杂的要求。
二.设计与分析:
题目一
一.题目要求:
本次作业主要考查公式的直接应用,计算逻辑相对简单。需要综合处理多种数据输入和计费流程,容易在多件货物计费逻辑和数据整合上出现错误。要求理解抽象的设计原则,并应用到实际代码中,对代码架构设计能力有一定要求。从总体上来说难度不大,没有什么在理解或算法上的困难。
代码类图如下:

代码分析如下:

一、整体概况
代码规模:
总行数 287 行,包含 6 个类(Flight、Customer、Cargo、ShippingInfo、Order、Main),平均每个类约 48 行,类规模适中。
方法总数 28 个,平均每个类 4.67 个方法,符合单一职责原则的基本要求。
复杂度分布:
最大复杂度为 5(Cargo.calculateBaseFare() 方法),其余方法复杂度普遍较低(多数为 1),整体复杂度可控。
平均复杂度 1.22,说明大部分方法逻辑简单,易于维护。
代码结构:
类之间通过组合 / 关联关系协作(如 Order 包含 Customer、ShippingInfo 和 Cargo 列表),符合合成复用原则。
输入输出逻辑集中在 Main 类,业务逻辑封装在 Cargo 和 Order 中,职责划分较清晰。
二、 面向对象设计原则遵循情况
合成复用原则:
Order 通过组合 Customer、ShippingInfo 和 Cargo 实现功能,避免继承带来的强耦合,符合原则。
里氏代换原则:
无继承关系,暂不涉及子类替换父类的场景,当前设计中性。
开闭原则:
Cargo.calculateBaseFare 硬编码费率规则,新增费率需修改代码,违反开闭原则。建议通过策略模式优化,将费率计算抽象为接口:
依赖倒置原则:
ShippingInfo 通过字符串 flightNumber 关联 Flight,而非直接依赖 Flight 对象,耦合性较低,但无法利用 Flight 的方法(如获取起降城市),建议在 Order 中注入 Flight 对象,提升类型安全性。
三、反思:
优点:类职责划分清晰,基本遵循单一职责和合成复用原则,复杂度控制较好。
改进方向:
消除硬编码,增强可扩展性(开闭原则)。
补充输入验证和注释,提升健壮性和可读性。
应用设计模式优化关键逻辑(如策略模式、依赖注入)。
题目二


代码类图如下:

代码分析如下:

一、整体结构分析
- 代码规模与复杂度
行数(Lines):363 行
问题:单个文件行数过多,违背 “单一职责原则”,可能导致可读性和维护性下降。
建议:将 Main 类中的 main 方法逻辑拆分到独立的服务类(如 OrderService、InputService),遵循 “类职责单一” 原则。
类和接口(Classes and Interfaces):5 个
说明:包含 CargoType、UserType 两个接口和 NormalCargoType 等三个实现类,接口设计合理,符合策略模式。 - 方法与块深度
每个类的方法数(Methods per Class):21.20
问题:平均每个类方法数偏高,尤其是 Order 类包含过多职责(如运费计算、报表生成、订单管理)。
建议:将 Order 类的报表生成逻辑(generateOrderReport、generateCargoReport)拆分到独立的 ReportGenerator 类。
最大块深度(Maximum Block Depth):5
出现位置:代码第 320 行(可能在 main 方法的多层循环或条件判断中)。
问题:块深度过深(如多层嵌套的 if-else、for 循环)会降低代码可读性,增加调试难度。
示例:main 方法中输入处理的多层嵌套(如货物类型选择的 switch 语句)。
建议:使用提前返回(Early Return)或提取方法(如 getCargoTypeFromInput)简化嵌套逻辑。
二、代码质量指标 - 注释比例
含注释的行百分比(Percent Lines with Comments):13.5%
问题:注释比例较低,关键逻辑(如体积重量计算、费率策略)缺少必要说明,影响后续维护。
建议:
在 Cargo 类的 calculateVolumeWeight 方法中添加注释,说明公式来源(如 “根据航空货运标准,体积重量 = 长 × 宽 × 高 / 6000”)。
在 Order 类的 calculateTotalFare 方法中注释折扣计算逻辑。 - 方法复杂度
最大复杂度(Maximum Complexity):0
说明:工具未检测到方法复杂度(可能因未正确识别方法逻辑)。
实际潜在问题:
main 方法包含大量输入处理逻辑(约 200 行),属于 “神级方法”(God Method),复杂度实际较高。
建议:将 main 方法拆分为多个小方法,如 inputFlightInfo、inputCargoDetails,每个方法专注单一任务。 - 块深度分布
块深度为 5 的语句数:7 行
问题:深度为 5 的块(如 for 循环中嵌套 switch 和多层 if)可能导致 “面条式代码”。
示例:main 方法中货物信息输入的循环内,嵌套 switch(货物类型选择)和参数校验。
建议:
将参数校验逻辑(如 validatePositiveValues)从 Cargo 类的构造方法中提取为公共方法,或使用异常处理增强可读性。
对 switch 语句使用策略模式进一步解耦(如通过映射表获取 CargoType 实例)
三、设计模式与架构改进 - 策略模式的应用
优点:CargoType 和 UserType 的策略模式设计清晰,便于扩展新的货物类型或用户折扣。
改进点:可通过枚举类(Enum)优化策略类的实例化,避免 switch-case 硬编码。
四.反思:
四、总结与优先级建议
main 方法臃肿 拆分为独立的输入、处理、输出方法,遵循 “单一职责”。
块深度过深 简化嵌套逻辑,提取公共方法或使用策略模式解耦。
注释不足 为关键算法、策略类和复杂逻辑添加注释。
类职责单一性 逐步将 Order 类的报表生成等功能拆分到独立类,提升可维护性。
三、踩坑心得
一、代码结构与设计模式的坑 - 神级方法(God Method)的陷阱
踩坑场景:
Main 类的 main 方法包含近 200 行代码,直接处理航班、客户、物流、货物等多阶段输入,逻辑层层嵌套(如 for 循环中嵌套 switch 和多层 if)。
后果:
代码可读性差,修改一处逻辑可能影响整个流程。
单元测试难以编写(输入逻辑与业务逻辑强耦合)。
避坑建议:
拆分职责:将输入、业务计算、输出分离到独立方法或类(如 InputService、OrderService、ReportService)。
遵循单一职责原则:每个类 / 方法只做一件事,例如 InputService 只负责读取用户输入,不涉及业务逻辑。 - 策略模式的不彻底应用
踩坑场景:
在选择货物类型时,使用 switch-case 硬编码映射到策略类(如 if (cargoTypeChoice == 1) new NormalCargoType())。
后果:
新增货物类型时需修改 switch-case,违背开闭原则(对扩展开放,对修改关闭)。
避坑建议:
使用枚举或映射表:通过枚举类或 Map<Integer, CargoType> 存储类型与策略的映射,
测试与异常处理的坑 - 未处理潜在异常
踩坑场景:
Cargo 类的构造方法抛出 IllegalArgumentException,但 main 方法未捕获该异常,导致程序直接终止。
后果:
用户输入非法参数(如负数)时,程序崩溃并显示堆栈跟踪,体验极差。
避坑建议:
在关键位置添加异常捕获
四、总结:
该代码通过策略模式实现了对于航空货运管理系统的灵活设计,但在代码结构、输入处理、可维护性等方面存在优化空间。通过遵循面向对象设计原则、规范编码习惯、完善异常处理和测试,可显著提升代码质量,使其更适应需求变化和团队协作开发。核心思路是:分而治之,抽象解耦,提前预防,持续优化。我通过本次对代码的深度剖析,不仅发现了具体的技术问题,更重要的是意识到开发思维和习惯的短板。未来需以 “可持续性开发” 为目标,在追求功能实现的同时,兼顾代码的可维护性、可测试性和可扩展性。
浙公网安备 33010602011771号