NCHU航空货运管理系统Blog
NCHU航空货运管理系统Blog
一、前言
对这两次题目集的总结:
大抵是在《面向对象程序设计》的苦海里泅渡了半载,这学习的进程,倒像是行至险峻的关隘,步步都是关键。堪堪捱到第九周,那第二次大作业便如同两座压顶的大山,轰然砸将下来。更兼两次迭代的 “磨难”,一层深似一层,横竖都要将我等在代码逻辑的严谨、类结构的妥帖,还有功能的完备上,逼出些真章来。此番,我便要将这两次迭代的种种,掰开了,揉碎了,细细地剖析、总结一番。
二、1.设计与分析
(一)1.1第一次航空货运管理题目的设计与分析
7-3 NCHU_航空货运管理系统(类设计)
一、计费重量的确定
空运以实际重量(GrossWeight)和体积重量(VolumeWeight)中的较
高者作为计费重量。
计算公式:
体积重量(kg)= 货物体积(长×宽×高,单位:厘米)÷6000
示例:
若货物实际重量为80kg,体积为120cm×80cm×60cm,则:
体积重量 =(120×80×60)÷6000=96kg
计费重量取96kg(因96kg>80kg)。
二、基础运费计算
费率(Rate):航空公司或货代根据航线、货物类型、市场行情等制定(如
CNY 30/kg)。本次作业费率采用分段计算方式:

公式:基础运费 = 计费重量 × 费率
三、题目说明
本次题目模拟某客户到该航空公司办理一次货运业务的过程:
航空公司提供如下信息:
航班信息(航班号,航班起飞机场所在城市,航班降落机场所在城市,航班
日期,航班最大载重量)
客户填写货运订单并进行支付,需要提供如下信息:
客户信息(姓名,电话号码等)
货物信息(货物名称,货物包装长、宽、高尺寸,货物重量等)
运送信息(发件人姓名、电话、地址,收件人姓名、电话、地址,所选
航班号,订单日期)
支付方式(支付宝支付、微信支付)
注:一个货运订单可以运送多件货物,每件货物均需要根据重量及费率单独
计费。
程序需要从键盘依次输入填写订单需要提供的信息,然后分别生成订单信
息报表及货物明细报表。
四、题目要求
本次题目重点考核面向对象设计原则中的单一职责原则、里氏代换原则、开
闭原则以及合成复用原则,除需要在PTA平台提交源码外,还需要在超星平台
提交本次作业最终得分源码(首次提交最高分源码)的类图,评判标准为:
基础得分:PTA实际得分
设计因素:单一职责原则(40%)、里氏代换原则(20%)、开闭原则(20%)、
合成复用原则(20%)
根据题目设计的类图:

1.1.2类的总体设计
1.遵循单一职责原则,每个类只负责一个特定的功能,如Customer类管理客户信息,Cargo类管理货物信息,Rate类专门计算运费。
2.采用封装机制,所有类的属性都使用private修饰,并通过公有的 getter 方法访问,隐藏内部实现细节,提供良好的封装性。
3.合理使用组合关系,Order类通过组合ContactInfo类来表示发件人和收件人信息,避免代码重复,提高代码的复用性。
Source Monitor分析结果:

1.1.3分析与心得
由上面的Source Monitor分析的结果来看不难发现,这次题目集提交的通过代码的存在的主要问题有这几个:
- 注释严重缺失
仅 2.4% 的行含注释,尤其是关键业务逻辑(如Rate类的运费计算规则、Main类的流程逻辑)未加说明,导致代码可读性差。 - 上帝方法(Main.main ())
Main.main()方法承担了输入读取、业务逻辑处理、结果输出等所有职责,代码长达 174 行,违反 “单一职责” 原则。 - 数据验证缺失
构造方法和业务方法(如Flight.addLoad)未对参数合法性进行校验(如重量是否为负数、字符串是否为空),可能导致运行时异常。 - 缺乏设计模式应用
代码中全为简单 POJO 和工具类,未使用继承、多态或设计模式(如工厂模式创建订单、策略模式处理不同费率),扩展性受限。 - 代码重复与冗余
Customer、Cargo等类的getter方法完全模板化,可通过 Lombok 的@Data注解简化(但需考虑项目依赖限制)。
改进措施:
- 增强代码可读性
添加注释:对业务规则(如体积重量计算逻辑)、复杂流程(如航班载重校验)、关键参数含义进行注释。 - 提升健壮性
参数校验:在构造方法和业务方法中添加合法性检查,抛出有意义的异常 - 优化业务逻辑复杂度
重构Rate.getRate():使用映射表替代多层if-else,提高可维护性。
(二)1.2第二次航空货运管理的设计与分析
1.2.1题目要求:
1.对于不同货物类型,有了不同的计算费率公式

2.运费计算公式新增折扣率
计算公式:基础运费 = 计费重量 × 费率 × 折扣率
其中,折扣率是指不同的用户类型针对每个订单的运费可以享受相应的折扣,
在本题中,用户分为个人用户和集团用户,其中个人用户可享受订单运费的9
折优惠,集团用户可享受订单运费的8折优惠。
3.可以使用多种方式支付,支付方式(支付宝支付、微信支付、现金支付)。
根据题目设计的类图:

1.2.2类的总体设计
- 基础类层次结构
Person 抽象基类
作用:作为客户、发件人、收件人的基类,封装通用属性
属性:name(姓名)、phone(电话)、address(地址)
特点:定义了基本信息的访问方法,通过抽象类实现代码复用
Customer 客户类
继承:Person 类
新增属性:customerID(客户编号)
特点:扩展了客户特有的标识属性,并提供独立的信息访问方法
Sender 发件人类 & Receiver 收件人类
继承:Person 类
特点:直接复用基类属性,未添加额外功能,仅作为类型标识 - 核心业务类
Cargo 货物类
属性:
基本信息:cargoType(类型)、cargoID(编号)、cargoName(名称)
物理属性:width(宽)、length(长)、height(高)、weight(重量)
功能:封装货物的所有属性,提供访问方法
Flight 航班类
属性:
航班信息:flightID(编号)、departAirport(出发机场)、arrivalAirport(到达机场)、departureTime(出发时间)
载重信息:maxLoad(最大载重)、currentLoad(当前载重)
核心方法:
addLoad():更新当前载重
canCarry():检查是否能承载指定重量
作用:管理航班的载重状态,确保货物运输可行性
Order 订单类
属性:
订单标识:orderID(编号)、orderDate(日期)
关联对象:Sender(发件人)、Receiver(收件人)、List(货物列表)
作用:整合订单的所有相关信息,作为数据传递的核心载体 - 策略模式实现
RateStrategy 费率策略接口
核心方法:
calculateVolumeWeight():计算体积重量
getRate():获取计费费率
calculateFreight():计算运费
作用:定义运费计算的策略接口,实现算法与业务的解耦
具体策略类
Normal、Expedite、Dangerous:
实现不同货物类型的基础费率计算
根据重量区间设置不同费率
StandardRate:与Normal策略逻辑相同,存在代码重复
DiscountRate:
装饰器模式应用,对基础策略添加折扣
根据客户类型(个人 / 企业)设置不同折扣率 - 工厂模式实现
Payment 支付接口
方法:getPaymentName() 获取支付方式名称
具体支付类
WechatPayment、AlipayPayment、CashPayment:实现不同支付方式
PaymentFactory 支付工厂
方法:createPayment() 根据输入创建对应支付对象
特点:使用 Java 14 的switch表达式简化对象创建逻辑 - 辅助功能类
Check 载重检查类
功能:检查航班是否能承载所有货物
核心方法:Checkweight() 遍历货物检查载重,输出超载提示
Agent 代理类
功能:根据货物类型和客户类型选择费率策略
特点:封装策略选择逻辑,避免业务代码直接依赖具体策略类
Display 显示类
功能:格式化输出订单详情和运费计算结果
特点:集中处理输出逻辑,提高代码可读性
Source Monitor分析结果:

1.1.3分析与心得
从提供的代码指标数据来看,相比之前的版本,代码结构和复杂度有一定改善,但仍存在一些可优化的方向。
设计问题:
策略类重复:Normal与StandardRate实现完全相同,存在代码冗余
命名不一致:getCargos()(复数)与实际返回单个Cargo对象的逻辑不符
职责模糊:Display类同时处理数据计算和格式化输出,违反单一职责原则
复杂度风险:
虽然平均复杂度低,但Agent类的策略选择逻辑存在 3 层嵌套(if-else if)
度量异常:Dangerous.getCargos()方法出现多次复杂度统计,可能是工具误将构造函数或同名方法重复计算
优化方面:
重构策略实现:
合并Normal与StandardRate类,避免代码重复
使用策略工厂模式替代条件判断,降低块深度
规范命名与职责:
将getCargos()重命名为getCargo(),匹配实际功能
拆分Display类,将数据计算与输出格式化解耦
增强代码可维护性:
为高复杂度方法添加注释,说明业务逻辑
对重复代码(如体积重量计算)提取为工具方法
总结
该代码实现了航空货运系统的核心功能,整体结构清晰且复杂度较低,但存在以下改进空间:
设计层面:策略模式的实现存在冗余,工厂模式可进一步优化
代码质量:部分方法命名不规范,存在重复逻辑
可维护性:注释覆盖不足,高复杂度方法需重构
心得:
当前代码在方法拆分和嵌套层级上有一定改进,但仍存在方法识别异常、分支逻辑复杂等问题。通过引入设计模式、进一步解耦职责和优化嵌套结构,可显著提升代码的可维护性和扩展性。还需要加强结合具体代码逻辑,优先处理方法定义问题的能力,再逐步重构调度策略部分。
三、踩坑心得
这次迭代作业相对于上次迭代作业降低了很多,但在设计上还是踩了非常多坑。
(一)字符串的输入没有注意清空,导致非零返回,导致浪费了大量时间去debug。。。。
(二)注意审题,没有清楚的审题那么做题目就是徒劳。导致找不出错误,最后还是让通过的室友帮我找到了错误。

(三)对于继承与多态的使用,构建框架还是不熟练,需要反复重新设计。
四、改进建议
一、设计模式优化
合并重复策略类
问题:Normal和StandardRate类实现完全相同,存在代码冗余
方案:删除StandardRate类,统一使用Normal类
重构 Agent 类,简化策略获取逻辑,避免重复代码
二、代码结构优化
重命名方法,将getCargos()改为getCargo(),匹配实际返回单个货物对象的逻辑,修正所有类中的方法命名,保持一致性,拆分 Display 类职责,分离数据计算与格式化输出
优化 Main 方法,将主方法中的控制流拆分为独立服务
三,适当增加注释,以便于下一次迭代。
五,总结
收获
一、Java 编程基础能力提升
面向对象编程实践
类与对象设计:通过抽象Person基类和Customer/Sender/Receiver子类,理解继承关系与代码复用
封装原则:通过private修饰符和getter方法实现数据封装,建立「接口隔离」思维
多态应用:通过RateStrategy接口实现不同费率策略,理解「同一接口,多种实现」的多态性
核心数据结构应用
List 集合操作:使用ArrayList存储货物列表,掌握add/get/remove等高频操作
泛型使用:通过List
对象引用关系:理解Order类中List
异常处理与输入验证
输入合法性检查:通过Check类验证航班载重,建立「输入验证优先」的开发习惯
类型转换处理:使用Double.parseDouble()进行数值转换,理解异常风险
二、设计模式的实战应用
策略模式(Strategy Pattern)
核心理解:将费率计算算法封装为独立策略类(Normal/Expedite/Dangerous),通过接口动态切换
应用场景:不同货物类型(普通 / 加急 / 危险品)的差异化费率计算,消除多层if-else嵌套
优势体会:代码扩展性提升,新增策略时无需修改原有逻辑
工厂模式(Factory Pattern)
实践应用:通过PaymentFactory创建不同支付方式对象,解耦对象创建与使用
Java 特性结合:使用 Java 14 的switch表达式优化工厂逻辑,提升代码简洁性
设计原则:遵循「依赖倒置原则」,依赖接口而非具体实现类
装饰器模式(Decorator Pattern)
功能扩展:DiscountRate装饰器为基础策略添加折扣功能,实现费率计算的动态组合
与继承对比:理解装饰器比继承更灵活的扩展方式,避免子类爆炸问题
三、业务逻辑与问题解决能力
物流业务模型抽象
领域建模:将航空货运场景抽象为Cargo/Flight/Order等核心实体,理解业务对象间的关系
运费计算逻辑:掌握「体积重量计算→计费重量确定→费率匹配→运费计算」的完整流程
载重约束处理:通过Flight.canCarry()方法实现航班载重限制的业务规则
复杂问题拆解能力
模块化设计:将系统拆分为「客户管理→货物处理→航班调度→订单管理→运费计算」等模块
逻辑分层:区分输入层(Main)、业务层(Agent/Check)、输出层(Display)的职责
迭代开发思维:从基础功能(载重检查)到复杂逻辑(折扣计算)逐步实现,降低开发复杂度
边界条件处理
载重溢出处理:当航班无法承载货物时的错误提示与流程终止
计费重量判断:通过Math.max()处理体积重量与实际重量的边界情况
默认值处理:支付方式工厂的默认现金支付,避免空指针异常
四、代码质量与工程化思维
代码规范意识
命名规范:理解类名(UpperCamelCase)、方法名(lowerCamelCase)的命名原则
格式统一:通过缩进、空行、运算符空格提升代码可读性
注释原则:关键逻辑添加注释(如费率计算规则、载重检查流程)
性能与效率认知
数据结构性能:理解ArrayList.remove(0)的 O (n) 复杂度,为后续选择LinkedList做铺垫
算法复杂度:策略选择从 O (n) 条件判断优化为 O (1) 映射表查询
资源管理:通过Scanner读取输入,理解资源释放的重要性(虽然代码中未体现)
可维护性设计
单一职责原则:每个类专注于单一功能(如Display仅负责输出)
开闭原则:通过策略模式实现「对扩展开放,对修改关闭」
依赖倒置原则:高层模块(Agent)依赖抽象接口(RateStrategy)而非具体类
五、编程思维与方法论提升
抽象思维培养
从具体到抽象:将现实中的「人」抽象为Person类,提取共同属性与行为
接口抽象能力:通过RateStrategy接口抽象费率计算的核心行为,屏蔽具体实现差异
逻辑推导能力
业务流程推导:从「客户下单→货物称重→航班分配→运费计算」推导代码执行流程
条件逻辑设计:根据重量区间(<20/20-50/50-100/>100)设计费率策略的条件分支
问题调试思路
分段验证:通过Check类独立验证航班载重,便于定位问题
输出调试法:利用System.out.printf打印中间变量(如计费重量、运费)辅助调试
错误处理流程:当载重不足时立即终止程序,避免无效操作
六、进阶知识拓展铺垫
设计模式深化
策略 + 工厂组合:理解策略工厂如何简化策略对象的创建与管理
装饰器模式延伸:为后续学习InputStream/OutputStream等 Java IO 装饰器模式打下基础
并发编程基础
线程安全思考:Flight.currentLoad在多线程环境下的安全问题,为后续学习同步机制做准备
数据一致性:货物重量与航班载重的原子性操作思考
工程化实践
模块化思想:理解代码分包的重要性(如将实体类、策略类、工具类分模块存放)
测试驱动开发(TDD):为Check/Agent等核心类设计单元测试用例的思路
不足
1.算法逻辑与代码质量
过度依赖if-else的优化策略
问题本质:条件逻辑嵌套反映出「过程式编程思维」,缺乏对抽象策略的应用。
2.注释与可读性优化
问题影响:缺乏逻辑注释会导致代码「自我解释性」不足。
浙公网安备 33010602011771号