航空货运管理系统-第八,九次作业博客
一、前言:
知识点考察:
主要考察了对类的封装、继承、多态和抽象类的使用。题目中要求使用了七大设计原则,如单一职责原则、里氏代换原则、开闭原则、合成复用原则等,规范了我们对这些设计原则的使用。
题量与难度:
这次的题目集难度不算很高,按照题目所给的要求完成即可,题量也算比较合适,前两道题较为简单,让我们有更多的时间去思考最后一题。这次的题目并未涉及到复杂算法的考察,更多的是对类的设计的考察,包括类的定义与封装机制、抽象类、ArrayList等的运用。
二、设计与分析
第一次作业:
本次题目模拟某客户到该航空公司办理一次货运业务的过程: 航空公司提供如下信息: 航班信息(航班号,航班起飞机场所在城市,航班降落机场所在城市,航班 日期,航班最大载重量) 客户填写货运订单并进行支付,需要提供如下信息:
- 客户信息(姓名,电话号码等)
- 货物信息(货物名称,货物包装长、宽、高尺寸,货物重量等)
- 运送信息(发件人姓名、电话、地址,收件人姓名、电话、地址,所选 航班号,订单日期)
- 支付方式(支付宝支付、微信支付)
注:一个货运订单可以运送多件货物,每件货物均需要根据重量及费率单独计费。
这个题目是一个航空货运订单系统,用于计算货物的运费并生成订单信息。它采用了面向对象的设计思想,通过类的继承和多态实现了灵活的费率计算策略。
核心功能:
-
数据输入与存储:输入并存储客户信息(姓名、电话等)、货物信息(名称、尺寸、重量)、航班信息(航班号、起降地、日期、最大载重)、订单信息(发件人 / 收件人信息、支付方式等);支持单个订单包含多件货物,每件货物单独计算费用。
-
计费逻辑实现:
- 计费重量:取实际重量与体积重量(长 × 宽 × 高 ÷6000)的较大值,示例中体积重量计算逻辑与代码一致。
- 分段费率:根据计费重量分为四档(<20kg、20-50kg、50-100kg、≥100kg),对应费率分别为 35 元 /kg、30 元 /kg、25 元 /kg、15 元 /kg,基础运费为计费重量 × 费率。
-
载重规则校验:检查订单总重量是否超过航班最大载重,若超限则拒绝承运。
-
订单列表生成:输出订单信息报表(客户信息、航班信息、发件 / 收件人信息、总重量、总费用)和货物明细报表(每件货物的计费重量、费率、运费)。
面向对象设计原则:
- 单一职责原则(SRP):
Customer
类仅存储客户信息,Cargo
类专注于货物属性与计费重量计算,Flight
类封装航班信息,Order
类处理订单业务逻辑(费用计算、载重校验、报表打印),RateStrategy
及其子类负责费率计算。 - 里氏代换原则(LSP):通过抽象类
RateStrategy
定义费率计算接口,SegmentedRateStrategy
实现具体策略,子类可无缝替换父类,符合里氏代换原则。 - 开闭原则(OCP):费率策略通过抽象类实现扩展,新增费率规则时无需修改现有
Order
类代码,只需创建新的RateStrategy
子类,符合 “对扩展开放,对修改关闭” 原则。 - 合成复用原则(CRP):
Order
类包含List<Cargo>
、Flight
、RateStrategy
等成员变量,通过组合复用功能,而非继承。
以上是代码的类图
- Customer 类:存储客户基本信息(ID、姓名、电话、地址),提供基本的 getter 方法。
- Cargo 类:表示货物,计算体积重量和计费重量(实际重量与体积重量中的较大值)。
- Flight 类:记录航班信息(航班号、起降地、日期、最大载重)。
- RateStrategy 抽象类:定义费率计算策略的接口,由
SegmentedRateStrategy
实现具体的分段计费逻辑。 - Order 类:核心业务类,负责计算总重量、总运费,打印订单信息,并检查航班载重是否超限。
- Main 类:程序入口,处理用户输入并创建订单。
这是powerdesigner生成的复杂度图
代码规模相关
- Lines:代码总行数为 224 行。
- Statements:语句数量为 163 条。
- Percent Branch Statements:分支语句占比 6.1% ,说明代码中分支逻辑(如
if - else
、switch
)的比例情况。 - Method Call Statements:方法调用语句有 54 条。
代码结构方面
- Classes and Interfaces:代码中类和接口的总数为 7 个。
- Methods per Class:平均每个类的方法数为 2.57 个。
- Average Statements per Method:平均每个方法的语句数为 5.89 条。
- Line Number of Most Complex Method:最复杂方法的行号是 92 ,对应方法为
SegmentedRateStrategy.calculate()
。
代码复杂度情况
- Maximum Complexity:最大复杂度为 5 ,对应方法同样是
SegmentedRateStrategy.calculate()
。 - Line Number of Deepest Block:最深代码块所在行号为 130 。
- Maximum Block Depth:最大代码块深度为 3 。
- Average Block Depth:平均代码块深度为 1.70 。
- Average Complexity:平均复杂度为 1.56 。
这个由powerdesigner生成的关于代码复杂度的图中可以读出本次代码的复杂度较低,复杂度最高的部分是题目中所给的分段计费函数,整段代码平均复杂度较低。由此可见,本次代码可能由于没有复杂的算法导致代码整体的复杂度不算很高,平均深度、最大复杂度等均在合理范围。
第二次作业:
这次题目在原有基础上进行了需求扩展,新增了货物类型和用户类型的计费规则:
-
货物类型与分段费率
- 货物分为普通货物、危险货物、加急货物三类,每类对应不同的分段费率规则:
- 普通货物:费率与原规则一致(35/30/25/15 元 /kg)。
- 危险货物:低重量段费率更高(80/50/30/20 元 /kg)。
- 加急货物:费率介于前两者之间(60/50/40/30 元 /kg)。
- 公式变化:基础运费计算公式新增折扣率,需结合用户类型计算最终费用。
- 货物分为普通货物、危险货物、加急货物三类,每类对应不同的分段费率规则:
-
用户类型与折扣机制
- 用户分为个人用户(9 折)和集团用户(8 折),折扣应用于整个订单的总运费,而非单件货物。
-
输入与输出扩展
- 新增输入:货物类型(需为普通 / 危险 / 加急)、用户类型(个人 / 集团)。
- 输出调整:订单报表需显示用户类型、折扣率及折扣后总金额,货物明细需标注货物类型及对应费率。
一、类设计与扩展
1. 用户类型与折扣机制
-
抽象类
Customer
- 新增抽象方法
getDiscountRate()
,由子类实现具体折扣逻辑:Individual
(个人用户)返回0.9
折,Corporate
(集团用户)返回0.8
折。
- 新增抽象方法
-
职责分离
- 用户类型信息独立于
Order
类,通过构造函数注入,遵循单一职责原则。
- 用户类型信息独立于
2. 货物类型与费率策略
-
抽象类
Cargo
- 新增抽象方法
RateStrategyMethod()
,由子类实现不同货物的费率计算:NormalCargo
(普通货物)、ExpeditedCargo
(加急货物)、DangerousCargo
(危险货物)分别实现分段费率逻辑,与题目要求一致。
- 通过多态实现费率策略扩展,符合开闭原则,新增货物类型时无需修改现有代码。
- 新增抽象方法
-
策略模式应用
- 费率计算逻辑封装在
Cargo
子类中,Order
类通过调用RateStrategyMethod()
解耦具体策略,符合合成复用原则。
- 费率计算逻辑封装在
3. 支付方式扩展
- 抽象类
Payment
- 定义支付方式接口,
Alipay
、Wechat
、Cash
实现具体支付逻辑,符合单一职责原则。 Order
类组合Payment
对象,通过多态调用支付方法,体现依赖倒转原则(高层模块依赖抽象接口)。
- 定义支付方式接口,
二、逻辑实现
1. 计费流程
-
计费重量计算
- 沿用
getChargeableWeight()
方法,取实际重量与体积重量的较大值,与上题一致。
- 沿用
-
总运费计算
- 步骤:
- 遍历货物,计算单件运费(计费重量 × 货物类型费率);
- 累加所有货物运费,乘以用户类型折扣率(
customer.getDiscountRate()
)。
- 步骤:
2. 输入处理与验证
- 用户类型验证
- 通过
equal
输入判断是否为Individual
或Corporate
。
- 通过
- 货物类型验证
- 通过
switch-case
匹配Normal
/Expedite
/Dangerous
。
- 通过
- 支付方式验证
- 也是通过
equal
校验输入是否为ALiPay
/Wechat
/Cash
。
- 也是通过
以上是代码的类图
这次的类图与上一次作业的类图大部分一致,本次作业主要是新增了用户类型折扣和货物类型费率策略,只需要对上次的代码做出一点修改即可,此处不对这次的类图做过多赘述。
这是由powerdesigner生成的代码复杂度图
代码规模相关
- Lines:代码总行数 331 行。
- Statements:语句数量 221 条。
- Percent Branch Statements:分支语句占比 14.0% ,比之前有所上升。
- Method Call Statements:方法调用语句 57 条。
代码结构方面
- Classes and Interfaces:类和接口总数达 13 个,功能模块划分更细。
- Methods per Class:平均每个类的方法数为 2.23 个 。
- Average Statements per Method:平均每个方法的语句数是 4.76 条 。
- Line Number of Most Complex Method:最复杂方法行号为 114,是
ExpeditedCargo.RateStrategyMethod()
。
代码复杂度情况
- Maximum Complexity:最大复杂度为 5 ,出现在
ExpeditedCargo.RateStrategyMethod()
。 - Line Number of Deepest Block:最深代码块行号 285 。
- Maximum Block Depth:最大代码块深度为 5 。
- Average Block Depth:平均代码块深度 1.86 。
- Average Complexity:平均复杂度 1.57 。
本次由powerdesigner生成的代码复杂度的图表与上次作业的代码复杂度总体上都差不多,最大复杂度都是货物的计费策略,平均复杂度也不高,和上次基本一样。
三、采坑心得
第一次作业
1.在第一次作业的提交中,我想当然的以为订单总重量就是实际重量,正因如此以为,我的代码一直过不了测试,一直是答案错误,因为给出的样例正好是计费重量等于实际重量,导致就算而我仔仔细细的比较了自己的输出与所给样例的每一处地方,都没找出来错误到底在哪里,让我摸不着头脑,后来想到pta开通了讨论区,去看了一下后发现有人和我有同样的问题,有人解答这个问题后我才知道原来是自己的固有思维限制了我找出错误的能力。
第二次作业
1.在这次作业中对于支付方式的输入验证方面,我一开始想的是直接从输入中使用nextline读取paymentmethod,但发现读取之后只用paymentmethod无法很好的在程序里调用payment的方法,于是我新增了一个变量Payment payment,由paymentmethod来从输入中读取,经过equal与paymentmethod的比对判断来决定payment是属于哪种支付方式,这样就很好的解决了调用支付方式的问题。
四、心得体会
改进建议
- 不足:缺乏注释,不利于代码阅读和后期维护;部分方法复杂度较高,可能存在逻辑过于复杂的问题,影响代码可读性和可维护性。
- 改进建议:及时添加注释,解释关键逻辑和功能;对复杂度高的方法进行重构,拆分复杂逻辑,提高代码清晰度。
五、总结
学习收获
在完成题目集 8 和 9 的 "航空货运管理系统" 项目过程中,我在 Java 编程能力与面向对象设计思维上均收获了实质性成长。在技术实现层面,我已能够独立完成类的完整设计周期,包括属性的安全封装、方法的合理定义等。通过对业务场景的深入分析,我学会了如何构建层次清晰的类结构体系,将客户、货物、航班等现实业务实体通过合理的方法设计实现业务流程的数字化表达。在面向对象思想的应用方面,我对继承与多态的理解已从概念认知转化为实践能力。通过继承机制,我成功实现了基类代码的复用与扩展,同时利用子类对父类方法的重写特性,实现了业务逻辑的差异化表达。以支付模块的设计为例,我通过抽象支付接口并实现具体支付策略类,成功构建了可扩展的支付体系,充分体现了多态设计的灵活性与可扩展性。这种设计模式的应用,使系统架构具备了良好的开闭特性,实现了七大基本原则中的开闭原则。
我在代码结构、异常处理和测试方面仍有一定的改进空间。通过模块化设计、增强异常处理和引入单元测试,可以显著提升系统的健壮性和可维护性。在未来的项目实践中,我们应更加注重代码的可读性、可扩展性和可靠性。