第二次Blog作业——航空货运管理系统
目录
一、 前言(知识点、题量、难度)
1. 第一次航空货运管理系统
2. 第二次航空货运管理系统
3. 总结
二、 题目设计与分析
1. 第一次航空货运管理系统
2. 第二次航空货运管理系统
三、 踩坑心得
1. 第一次航空货运管理系统
2. 第二次航空货运管理系统
3. 踩坑总结
四、 改进建议
五、 总结
1. 面向对象编程的深入理解
2. 数据结构的选择与应用
3. 代码结构与可读性
4. 对教师、课程、作业、实验、课上及课下组织方式等方面的改进建议及意见

一、 前言
1. 第一次航空货运管理系统:
知识点:
融入了很多面向对象设计原则,比如,单一职责原则,里氏代换原则,开闭原则,数据结构上应用了数组存储多件货物信息,例如,通过List集合管理订单中的所有货物,便于遍历计算总重量和生成明细报表。
题量:
还可以,在可接受的范围内,有时间做,并且可以做完,时间相对宽松,不紧迫。
难度:
中等,感觉还行,逻辑规则不难比电梯简单,就是感觉题里的要素挺多的。
2. 第二次航空货运管理系统:
知识点:
考了类的设计与继承Customer类包含用户类型属性(个人用户,集团用户),通过方法getDiscountRate()返回对应折扣率(0.9或0.8),支付方式的扩展性,定义Payment接口(pay()方法),具体支付类(AlipayPayment、WeChatPayment、CashPayment)实现接口,还包含多层级输入处理,数据存储与遍历,格式化输出等知识。
题量:
中等,用了差不多一天的时间解决的这道题,题量不是很多主要是改的时候出现了错误导致做题时间较长。
难度:
较难,增加了很多子类,将本来的类变成父类,并且又扩展了支付方式。
3. 总结:
两次题目集逐步递进且不断增加复杂度。面向对象设计的深化应用:类职责单一化,将客户、货物、航班、订单等实体的属性与行为封装到独立类中。继承与多态的灵活性,通过父类定义通用接口,普通货物、危险货物等子类实现具体逻辑,利用里氏代换原则实现代码复用,同时也通过了开闭原则支持新增货物类型扩展。在做题的过程中,慢慢的随着题目复杂度增加,我逐渐意识到了设计原则对代码可维护性的关键作用,也要以 “高内聚、低耦合” 为设计目标,通过合理的类职责划分、继承与组合关系设计,以及策略模式等设计模式的运用,构建可扩展、易维护的代码结构。

二、 题目设计与分析
1. 第一次航空货运管理系统:
1.1 题目:第九周作业题目说明
1.2 功能设计:
请求输入与解析:用户通过控制台输入客户信息、货物信息、航班信息和订单信息。输入格式要求严格,程序通过 Scanner 类获取输入,并进行相应的解析和存储。
客户信息管理:Customer 类负责存储客户的 ID、姓名、电话和地址信息。程序通过用户输入创建 Customer 对象,并将其关联到订单中。
货物信息管理:Goods 类负责存储货物的 ID、名称、尺寸、实际重量等信息,并计算计费重量、计费费率和应交运费。程序通过用户输入创建多个 Goods 对象,并将其存储在列表中,与订单关联。
航班信息管理:Flight 类负责存储航班号、起飞机场、到达机场、航班日期和最大载量等信息。程序通过用户输入创建 Flight 对象,并将其关联到订单中。
订单信息管理:Order 类负责存储订单编号、订单日期、客户、货物列表、送货信息、支付方式和航班等信息。程序通过用户输入创建 Order 对象,并进行订单总重量计算、航班载重量检查以及生成订单信息报告和货物明细报告。
支付方式管理:Payment 类是一个抽象类,定义了支付的抽象方法。AlipayPayment 和 WeChatPayment 类实现了 Payment 类,分别表示支付宝支付和微信支付方式。程序默认使用微信支付方式。
送货信息管理:DeliveryInfo 类负责存储发件人姓名、电话、地址,收件人姓名、电话、地址以及航班号等信息。
报告生成:Order 类包含生成订单信息报告和货物明细报告的方法。订单信息报告包括客户信息、航班号、订单号、订单日期、发件人和收件人信息、订单总重量以及微信支付金额等;货物明细报告包括货物明细编号、货物名称、计费重量、计费费率和应交运费等。
异常处理:当用户输入的航班日期格式不正确时,抛出 IllegalArgumentException,提示用户正确的日期格式。
1.3 类图:

1.4 SourceMontor报告:

1.5 SourceMontor报告内容:
行数与语句数分析:
Main类中通过控制台输入获取各类信息(客户、货物、航班、订单等)并进行处理。代码总行数为 385 行,语句数为 153 条 。其中输入相关操作较多,导致行数相对较多。
分支语句占比分析:
分支语句占比为 3.9% 。代码中主要在检查航班载重量时使用了if-else语句(if (totalWeight > flight.getMaxLoad())),用于判断订单总重量是否超过航班最大载量,决定后续执行生成报告还是输出超载提示,分支逻辑不算复杂,所以占比相对较低。
方法调用语句分析:
方法调用语句有 49 条。在整个代码中,从获取输入创建各类对象(如new Customer、new Goods等),到调用对象的方法计算费用(如goods.determineChargeableWeight() 、goods.jisuanfreight() )、生成报告(order.generateOrderInfoReport(totalWeight) 、order.generateGoodsListInfoReport() )等操作,频繁进行方法调用,体现了对不同类功能的组合使用。
注释行占比分析:
注释行占比为 6.8% 。代码中注释主要用于对代码功能模块进行简单说明,如 “输入客户信息”“输入货物信息” 等,帮助理解代码逻辑,但注释整体数量不算多,占比较低。
类和接口数量分析:
代码中包含类和接口共 5 个 。分别是Main主类,以及业务相关的Order(订单类)、Customer(客户类)、Goods(货物类)、Flight(航班类) 等。
2. 第二次航空货运管理系统:
2.1 题目:
1.2 功能设计:
输入来源与格式:
用户通过控制台输入订单相关信息,按固定顺序输入各类数据,格式需符合以下规则:
客户类型:输入Individual(个体客户)或Corporate(团体客户)。
客户信息:根据类型输入客户 ID、姓名、电话、地址。
货物类型与数量:输入货物类型(Normal/Expedite/Dangerous)及数量,后续按数量输入每件货物的 ID、名称、长宽高、实际重量。
航班信息:输入航班号、起降机场、日期(格式YYYY-MM-DD)、最大载量。
订单基础信息:输入订单号、日期、收发件人信息及支付方式(Wechat/Alipay/Cash)。
解析逻辑:
使用Scanner逐行读取输入,根据输入顺序解析为对应的对象属性(如Customer、Goods、Flight等)。
对日期格式进行校验(通过SimpleDateFormat解析FlightDate,若格式错误抛出异常)。
支付方式解析为具体支付类(WeChatPayment/AlipayPayment/CashPayment)。
Order(订单):
封装订单核心信息(编号、日期、客户、货物列表、物流信息、支付方式、航班)。
计算基础运费(calculateBaseFreight),生成订单信息报告(generateOrderInfoReport)和货物明细报告(generateGoodsListInfoReport)。
通过多态判断支付方式名称(getPaymentName)。
Customer(客户抽象类):
定义客户基础属性(ID、姓名、电话、地址),提供抽象方法GetDiscountRate(个体客户折扣率 0.9,团体客户 0.8)。
Goods(货物抽象类):
定义货物基础属性(ID、名称、尺寸、实际重量),计算计费重量(determineChargeableWeight,取实际重量与体积重量的较大值)。
派生类(普通货物、危险货物、加急货物)实现不同运费费率计算逻辑(haveRate)。
Payment(支付抽象类):
定义支付抽象方法pay,具体子类(现金、支付宝、微信)实现不同支付方式的输出逻辑。
Flight(航班):
封装航班信息(航班号、起降机场、日期、最大载量),校验日期格式并存储为Date对象。
运费计算与逻辑处理
单件货物运费计算:
根据货物类型(普通 / 危险 / 加急)调用对应的费率规则(如普通货物:≤20kg 费率 35 元 /kg,20-50kg 费率 30 元 /kg 等)。
计费重量取实际重量与体积重量(长 × 宽 × 高 / 6000)的较大值。
订单总运费计算:
累加所有货物的基础运费,再根据客户类型应用折扣率(个体 9 折,团体 8 折)。
航班载量校验:
计算订单总计费重量,若超过航班最大载量,输出提示信息并终止订单处理;否则生成报告并执行支付。
输出内容与格式:
包含客户信息、航班号、订单号、日期、收发件人信息、总重量、支付方式及金额(格式化输出保留一位小数)等。
支付操作:
根据支付方式调用对应子类的pay方法,输出支付信息(如 “使用微信支付:XXX 元”)。
异常处理:
日期格式错误时抛出ParseException,并提示 “航班日期格式必须为 YYYY-MM-DD”。
支付方式不匹配时默认显示 “未知”,可扩展为抛出异常(当前代码未处理无效支付方式)。
1.3 类图:

1.4 SourceMontor报告:

1.5 SourceMontor报告内容:
时间复杂度分析:
由于未明确具体方法,但从整体代码行数等信息推测,对于简单的属性获取方法(如getCustomer、getOrderNumber等大量类似方法 ),仅涉及简单的返回操作,时间复杂度为 O (1) 。
calculateBaseFreight方法,需遍历goodsList,假设货物数量为 N,时间复杂度为 O (N) 。
generateOrderInfoReport和generateGoodsListInfoReport方法,前者输出固定格式信息,涉及少量字符串拼接和格式化输出,时间复杂度近似 O (1);后者需遍历goodsList,假设货物数量为 N,时间复杂度为 O (N) 。
getPaymentName方法,通过instanceof判断支付方式类型,最多进行 3 次判断,时间复杂度为 O (1) 。
各类货物(GeneralCargo、DangerousGoods、ExpressGoods)的haveRate方法,根据计费重量进行条件判断,假设判断条件数量为 K,时间复杂度为 O (K) ,一般 K 为常数,可视为 O (1) 。
Goods类的determineChargeableWeight和jisuanfreight方法,涉及简单算术运算和一次条件判断,时间复杂度为 O (1) 。
Flight类的构造方法中,日期解析操作假设输入字符串长度为 L,时间复杂度为 O (L) 。
main方法中,输入读取和处理部分:
读取各类输入信息,假设输入行数为 M,每次读取操作时间复杂度为 O (1),整体读取时间复杂度为 O (M) 。
遍历货物列表计算总重量和总费用,假设货物数量为 N,时间复杂度为 O (N) 。
整体main方法时间复杂度受输入处理和货物遍历等操作影响,主要为 O (M + N) 。
空间复杂度分析:
Order类包含多个属性(如goodsList等),假设goodsList中货物数量为 N,其他属性占用空间视为常数,空间复杂度为 O (N) 。
Customer类及其子类(IndividualCustomer、GroupCustomer),存储固定属性(ID、姓名等),空间复杂度为 O (1) 。
Goods类及其子类(GeneralCargo、DangerousGoods、ExpressGoods),存储固定属性(ID、名称等),空间复杂度为 O (1) 。
Payment类及其子类(CashPayment、AlipayPayment、WeChatPayment),存储固定属性,空间复杂度为 O (1) 。
DeliveryInfo类和Flight类,存储固定属性,空间复杂度为 O (1) 。
main方法中,使用Scanner存储输入信息,假设输入请求数量为 K,空间复杂度为 O (K) ;使用ArrayList存储货物列表,假设货物数量为 N,空间复杂度为 O (N) 。总体空间复杂度为 O (K + N) 。
圈复杂度分析:
大量简单的属性获取方法(如getCustomer、getOrderNumber等 ),圈复杂度为 1。
calculateBaseFreight方法,包含一个for循环,圈复杂度为 2。
generateOrderInfoReport方法,主要是格式化输出语句,圈复杂度为 1。
generateGoodsListInfoReport方法,包含一个for循环,圈复杂度为 2。
getPaymentName方法,包含多个if - else if条件判断,圈复杂度为 4。
各类货物(GeneralCargo、DangerousGoods、ExpressGoods)的haveRate方法,包含多个if - else if条件判断,圈复杂度约为 4。
Flight类的构造方法,包含一个try - catch块,圈复杂度为 2。
main方法,包含大量的if - else if条件判断和循环,圈复杂度较高,约为 8。

三、 踩坑心得
1. 第一次航空货运管理系统
非零返回:![image]()
小问题但是很容易疏忽,在EclipseIDE上写完代码后复制到PTA上忘记把最上面的包(package 货运;)删掉,找了很久为什么非零返回,结果发现是这个问题。。。
答案错误:![image]()
没有想清楚代码运算运费的逻辑分配,就比如Goods类的方法:Goods类中没有haveRate和jisuanfreight方法,在计算运费相关逻辑时,是在Order类的calculateBaseFreight和generateGoodsListInfoReport方法中直接进行条件判断来确定费率并计算运费。这样就会因为逻辑不清晰而出现错误,而最后我在Goods类新增了haveRate和jisuanfreight方法,逻辑更加清晰了,方便找到错误。
2. 第二次航空货运管理系统
编译错误:![image]()
变量未初始化,之后我在代码中添加客户类型验证:在读取客户类型后,立即检查是否为有效类型(Individual或Corporate)。如果类型无效,输出错误信息并终止程序,确保不会使用未初始化的customer变量。和支付方式验证:在读取支付方式后,立即检查是否为有效类型(Wechat、Alipay或Cash)。如果类型无效,输出错误信息并终止程序,确保不会使用未初始化的payment变量。
非零返回![image]()
输入处理不当,未处理非法输入,当程序期望特定格式或范围的输入时,没有对输入进行有效性检查和处理。之后我在代码主函数里添加try-catch-finally来校对输入。
直接创建了一个对象,没有给他赋予任何的东西,没有对他进行初始化,最后非零返回,发现问题后我把它先判为空。
答案错误![image]()
计算逻辑出错,忘记改运费逻辑,没有乘上用户折扣,属于有点粗心大意了。最后死活给加上了。
还有一个问题是输出顺序弄错了(找了三遍才发现真的很想笑了)。
3. 踩坑总结
注释太少。
非零返回,对输入格式处理不当,还有代码复制到PTA上疏忽包的删除,这是这次作业遇到的问题。
写代码之前没细致的思考运算规则和输入输出的格式,最后含泪收拾自己留下的烂摊子。。。。。。

四、 改进建议
1. 增加对注释的填写
方法注释:用 Javadoc 格式注释参数、返回值、异常(如calculateBaseFreight()需说明运费计算逻辑)。关键逻辑注释:在复杂算法、条件判断、循环处添加注释(如货物类型判断、费率计算规则)。
2. 解决非零返回这个心头大患
用try-catch处理可预期异常(如日期解析、文件读取),对可能为null的对象先判空再操作。使用正则表达式验证关键输入(如日期、电话号码)。读取整数后用scanner.nextLine()消耗换行符
3.细心可以规避75%的问题
拿到题目后不只要画出类图,更要把细节思考完善,一些小地方比如输出的顺序等是很重要的。

五、 总结
1. 面向对象编程的深入理解
类的设计与封装
在订单系统相关的代码中,同样定义了多个功能各异的类,如Order、Goods、Customer等,将订单处理相关的数据和操作封装在一起。以Goods类为例,它封装了货物的编号、名称、尺寸、重量等数据,以及计算计费重量、确定费率等操作方法。这种封装方式使得外部代码无需了解货物内部数据管理的细节,仅通过调用公开方法就能获取或修改货物信息,提升了代码的清晰度、可维护性与可扩展性。比如若要更改货物计费重量的计算方式,只需在Goods类内部修改,不会影响其他类的代码;若要添加新的货物类型相关功能,也可在该类中进行扩展,不会破坏整体代码结构。
类之间的关系
代码展示了多种类间关系,如关联和组合。Order 类与 Goods 类、Customer 类之间是关联关系,Order 类通过持有 Goods 和 Customer 的实例,协调它们之间的工作,完成订单处理。理解这些类间关系有助于构建合理的订单系统架构,使代码组织更有序,提高可读性、可维护性与可扩展性,方便后续功能的添加与修改。例如,当需要添加新的支付方式时,可以在 Payment 接口的基础上创建新的实现类,而无需修改 Order 类的核心逻辑,只需在创建订单时传入新的支付方式实例即可。
2. 数据结构的选择与应用
在订单处理流程部分,ArrayList被广泛用于存储动态变化的数据集合。像Order类中使用ArrayList存储订单中的货物对象列表,这种方式适合货物数量动态变化的场景,方便添加和删除货物。在处理订单的过程中,通过遍历这些列表,可以按顺序处理每个货物,例如在计算订单总重量、生成货物明细报告时,遍历列表对每个货物进行相应操作,充分发挥了列表便于顺序处理数据的优势。
3. 代码结构与可读性
方法和类的划分:
订单系统代码将不同功能划分到不同的类和方法中,如 Order 类负责订单信息管理,Goods 类管理货物属性与计费规则,Payment 接口及其实现类处理支付逻辑,每个类职责明确。在方法层面,各方法功能单一,如 Order 类中的 calculateBaseFreight 方法负责计算基础运费,generateOrderInfoReport 方法负责生成订单信息报告等。这种划分方式可以使代码逻辑清晰,易于理解和修改,方便其他开发者阅读和维护代码。
命名规范:
类名、方法名和变量名的命名较为规范,具有一定描述性。像 Order 类、Goods 类、Customer 类等类名,直观地表明了类的功能;determineChargeableWeight、haveRate 等方法名,清晰地表达了方法的作用;变量名如 grossWeight、chargeableWeight、senderAddress 等,也能准确反映其代表的数据含义。合理的命名在一定程度上提高了代码的可读性,尤其是对复杂算法和关键逻辑的解释,将进一步提升代码的可维护性。
4. 对教师、课程、作业、实验、课上及课下组织方式等方面的改进建议及意见
刚开始我不太理解课程和作业的安排,感觉上完课对作业无从下手,但是经过这几次的迭代,有了对面向对象更多的认识,也渐渐明白了老师在课上讲的内容的重要性,如果没有面向对象各大原则的认识,我想现在我才是无从下手的,现在写代码心里有底,但是在这节课的基础知识上感觉还是有所欠缺,虽然有书,但是没有时间去学习阅读,每周分给各科的时间都是有限的,现在各个数学也有难度,还是希望线下作业不要这么多,可以让我有更多的时间去夯实其他内容。






浙公网安备 33010602011771号