NCHU--OOP--BLOG2--航空货运管理系统
题目集 8-9 航空货运管理系统实践与反思
一、前言
在前两轮 PTA 作业中,我们已完成了两道航空货运管理系统的开发。这两个系统延续了迭代优化的思路,与此前的项目形成了有机的演进脉络。值得注意的是,相较于上一次作业,此次在算法实现的复杂度上有明显下降,但在代码设计层面却提出了全新挑战 —— 题目核心聚焦于面向对象七大原则的实践应用。这意味着本次开发的重点不再是算法攻坚,而是对抽象类设计、继承与多态机制、合成复用原则等面向对象核心知识的深度落地,在系统架构设计维度实现了难度的跃升。
二、设计与分析
题目集8单部电梯调度问题分析
题目如下:


需要生成如下格式订单:
客户:姓名(电话)订单信息如下:
航班号:
订单号:
订单日期:
发件人姓名:
发件人电话:
发件人地址:
收件人姓名:
收件人电话:
收件人地址:
订单总重量(kg):
微信支付金额:
货物明细如下:
明细编号 货物名称 计费重量 计费费率 应交运费
1 ...
2 ...
SourceMonitor报表分析

类图分析

分析与心得
一、求和操作符误用导致的总量计算异常
在计算多件货物总重量时,误将累加操作符+=写成赋值操作符=,代码如下:
for (Goods goods : goodsList) {
totalWeight = goods.getWeight(); // 错误:应为 totalWeight += goods.getWeight();
}
二、类图设计原则总结
- 单一职责(SRP):各分类功能独立(航班、货物、支付等模块职责明确)。
- 依赖倒置(DIP):
Order依赖Payment抽象,而非具体支付类(如WeChatPay)。 - 开闭原则(OCP):支付方式通过接口扩展(新增支付类不影响订单逻辑)。
- 里氏替换(LSP):
Sender/Receiver继承Person,可替换父类使用(行为兼容)。 - 接口隔离(ISP):
Payment接口仅含支付核心方法(避免冗余,专注单一职责)。
架构价值:可维护(模块职责清晰,修改风险低)、可扩展(新增功能快速迭代,无需改动核心逻辑)。
三、代码质量的深度剖析
通过 SourceMonitor 生成的代码分析报告,可以清晰地看出我提交的代码虽然通过了测试点,但在质量上存在不少问题:
一、代码规模方面
-
方法设计较为合理
- 平均每个方法包含3.3条语句,基本做到了功能单一,例如
Goods.getWeight()这类方法专注于数据获取,没有过多冗余操作。 - 最大方法复杂度为5(
Goods.getRate()),在处理费率分段计算时,逻辑层次相对清晰,没有出现过于复杂的嵌套结构。
- 平均每个方法包含3.3条语句,基本做到了功能单一,例如
-
代码结构紧凑
- 484行代码包含263条可执行语句,代码密度适中,没有明显的空行或无效注释,整体结构较为简洁。
- 类与接口数量控制在3个,在项目初期阶段,这种设计有助于快速实现功能,减少不必要的抽象层级。
二、代码质量层面
-
逻辑控制较为清晰
- 分支语句占比5.3%,主要集中在核心业务逻辑(如费率计算),且嵌套层级较浅(最大深度3层),流程控制基本合理。
- 方法间调用关系明确,例如
Order.getTotalMoney()依赖Goods.getBasicMoney(),模块间协作关系较为直观。
-
遵循基础编码规范
- 采用标准的Java Bean命名规范(
getter/setter方法),如Goods.getName()、Order.setOrderID(),代码可读性较好。 - 多数方法圈复杂度为1(如
Agent.getCustomer()),实现了简单功能的快速封装。
- 采用标准的Java Bean命名规范(
三、类设计角度
-
组合关系的基本应用
Order类通过getGoods()方法持有Goods实例,建立了“订单-货物”的组合关系,避免了过度继承带来的耦合问题。Agent类封装了客户、航班等信息的获取逻辑,通过属性注入的方式实现了基本的依赖管理。
-
功能模块化的初步尝试
Goods类将货物属性(长宽高、重量)与基础计算(计费重量、运费)封装在一起,虽然存在一定职责重叠,但实现了基础功能的内聚。Order.show()方法集中处理报表展示逻辑,调用getTotalMoney()等计算方法,体现了“数据处理与展示分离”的初步意识。
-
扩展性的潜在可能
- 费率计算采用分段函数(
if-else)实现,虽然目前未完全符合开闭原则,但逻辑集中在Goods.getRate()方法中,为后续重构预留了一定空间。 - 类间通过方法调用而非直接属性访问(如
Order.getAgent()),保留了接口抽象的可能性。
- 费率计算采用分段函数(
四、数据交互合理性
-
输入输出流程清晰
Order.show()方法通过多次调用其他方法(如getTotalWeight())完成数据聚合与展示,流程较为清晰,符合基本的业务逻辑。Goods.getChargeableWeight()方法正确实现了“体积重量=长×宽×高/6000”的业务公式,计算逻辑准确。
-
数据封装基本到位
- 所有属性通过
getter/setter方法访问,确保了数据的封装性,例如Goods.setWeight()方法对属性的访问控制。 Order类通过getTotalWeight()方法聚合多件货物的重量,保证了数据计算的一致性。
- 所有属性通过
测试通过截图

题目集9单部电梯调度问题分析
题目如下:



生成的订单同上次
SourceMonitor报表分析

类图分析

分析与心得
一、代码规模
- 行数:Main.java有 573 行代码,从规模上看不算特别少。但注释率仅 0.7%,这意味着代码中对核心逻辑的解释极度匮乏。像货物重量计算、航班承载判断等关键业务逻辑处,缺乏注释会让后续接手代码的人一头雾水。
- 分支与调用:分支语句占比 9.0% ,要留意那些嵌套深度超过 3 层的分支结构,过深的嵌套往往意味着逻辑过于复杂,可维护性差。有 75 个方法调用,我们得审视每个方法是否真的做到了职责单一,有没有一个方法干了多件事的情况。
二、代码质量
- 分支优化:查看Block Histogram 发现部分代码块深度较大。比如在一些涉及业务规则判断的地方,可能存在多层if - else嵌套。可以把这些复杂的嵌套逻辑提取出来,封装成独立的方法,让代码逻辑更清晰。
- 注释补充:对于像Flight.canCarry(判断航班能否承载货物)、Payment.pay(支付操作)等核心逻辑方法,必须添加注释。注释要说明方法的功能、输入参数的含义、返回值的意义等,方便他人理解和维护代码。
三、类设计(结合类图分析) - 单一职责原则(SRP:Goods类负责货物相关属性和操作,Flight类管理航班信息,Payment类处理支付,职责相对清晰。但Order类可能承担了过多职责,比如既负责订单数据管理,又进行一些复杂的计算逻辑。可以考虑把计算逻辑分离出来,比如单独创建一个OrderCalculator类来专门处理订单的计算,让Order类专注于订单数据的存储和基本操作。
- 依赖倒置与开闭原则(DIP/OCP):支付模块设计得比较好,通过接口来定义支付行为,WeChatPay、CashPay等具体支付方式去实现这个接口。这样如果要新增支付方式(比如添加一种新的电子钱包支付方式),不需要修改Order类等高层模块的代码,符合开闭原则。对于Flight类的载重规则,也可以进一步接口化,方便未来根据不同的业务场景(比如不同的航班类型有不同载重标准)进行扩展。
- 里氏替换与接口隔离原则(LSP/ISP):Sender和Receiver继承自Person,在使用上可以互相替换,并且行为保持一致,满足里氏替换原则。Payment接口定义得比较精简,只包含了pay相关的方法,没有冗余的操作,符合接口隔离原则。但对于其他类的接口设计,也需要进一步检查是否存在类似 “胖接口” 的问题。
耦合度:从类图看,模块之间的依赖关系比较清晰,没有出现复杂的循环依赖情况。不过像货物载重计算这种复杂的计算逻辑,可以进一步提取成独立的服务类,降低类与类之间因为复杂计算带来的耦合度,提高代码的可测试性和可维护性。
四、优化建议
- 规模方面:赶紧补上核心逻辑的注释,让代码 “自解释”。同时,对于那些较长、功能复杂的方法,拆分成多个功能单一的小方法。
- 质量方面:仔细梳理分支结构,简化深度大的嵌套。并且始终牢记每个方法只做一件事,保证方法的职责单一性。
- 设计方面:充分利用抽象接口来解耦不同模块。对于新增功能,先思考是否符合开闭原则,不要出现硬编码的情况,提高代码的扩展性和灵活性。
测试通过截图

三、踩坑心得
类职责划分模糊导致的耦合问题
初期设计时,Order类同时承担订单信息存储、货物运费计算和支付流程处理,例如getTotalMoney()方法直接调用Goods的计费逻辑,违背单一职责原则。当需要新增货物类型时,不得不修改Order和Goods两个类,代码维护成本激增。
支付模块扩展性不足
支付方式通过if-else判断实现(如if(pay.equals("Wechat"))),未抽象为接口。新增支付方式时需修改Main类的调用逻辑,违反开闭原则。例如添加BankPay时,必须修改订单处理流程,导致系统扩展性差。
业务逻辑与代码实现的偏差
在Goods.getRate()方法中,费率计算的重量分段条件虽覆盖了业务需求,但未提取为独立策略类。例如普通货物费率的分段逻辑(<20kg、20-50kg)直接硬编码,后续若调整费率规则需修改多处代码,存在维护风险。
四、总结
设计原则的实践价值
通过接口抽象(如Payment)和职责拆分(Order类),系统扩展性显著提升。新增支付方式或货物类型时,只需扩展实现类,核心逻辑无需修改,验证了开闭原则的有效性。
代码质量的改进方向
目前Goods类仍混合了数据属性与计算逻辑(如getChargeableWeight()),可进一步拆分为GoodsEntity(存储属性)和GoodsCalculator(处理计算),强化单一职责。
注释率不足的问题需改善,例如在Flight.canCarry()方法中添加业务注释,说明载重校验规则,提升代码可读性。
面向对象思维的提升
本次实践深刻体会到 “组合优于继承” 的设计思想,如Order类通过组合Agent、Goods等对象实现功能,而非过度继承,降低了类间耦合。未来开发中需优先考虑接口抽象与模块解耦,避免 “大泥球” 式代码结构。

浙公网安备 33010602011771号