NCHU--第二次Blog作业
第8-9作业的结束了,我学习到了以下知识点:
1.多态的使用
2.继承的使用
3.抽象的使用
Complexity Metrics(复杂度分析)
因为下面要用到复杂度分析,所以先在此给出一些相关概念。
我们需要使用的主要是方法和类的复杂度分析。
方法的复杂度分析主要基于循环复杂度的计算。循环复杂度是一种表示程序复杂度的软件度量,由程序流程图中的“基础路径”数量得来。
ev(G):即Essentail Complexity,用来表示一个方法的结构化程度,范围在[1,v(G)]之间,值越大则程序的结构越“病态”,其计算过程和图的“缩点”有关。
iv(G):即Design Complexity,用来表示一个方法和他所调用的其他方法的紧密程度,范围也在[1,v(G)]之间,值越大联系越紧密。
v(G):即循环复杂度,可以理解为穷尽程序流程每一条路径所需要的试验次数。
对于类,有OCavg和WMC两个项目,分别代表类的方法的平均循环复杂度和总循环复杂度。
下面我将从程序结构,公测、互测以及bug分析几个方面来总结我第一单元的三次作业。
第一次作业——题目集8
题目:
航空快递以速度快、安全性高成为急件或贵重物品的首选。本题目要求对航空货运管理系统进行类设计,具体说明参看说明文件。
OO第九周作业题目说明.pdf
输入格式:
按如下顺序分别输入客户信息、货物信息、航班信息以及订单信息。
客户编号
客户姓名
客户电话
客户地址
运送货物数量
[货物编号
货物名称
货物宽度
货物长度
货物高度
货物重量
]//[]内的内容输入次数取决于“运送货物数量”,输入不包含“[]”
航班号
航班起飞机场
航班降落机场
航班日期(格式为YYYY-MM-DD)
航班最大载重量
订单编号
订单日期(格式为YYYY-MM-DD)
发件人地址
发件人姓名
发件人电话
收件人地址
收件人姓名
收件人电话
输出格式:
如果订单中货物重量超过航班剩余载重量,程序输出The flight with flight number:航班号 has exceeded its load capacity and cannot carry the order. ,程序终止运行。
如果航班载重量可以承接该订单,输出如下:
客户:姓名(电话)订单信息如下:
航班号:
订单号:
订单日期:
发件人姓名:
发件人电话:
发件人地址:
收件人姓名:
收件人电话:
收件人地址:
订单总重量(kg):
微信支付金额:
货物明细如下:
明细编号 货物名称 计费重量 计费费率 应交运费
1 ...
2 ...
注:输出中实型数均保留1位小数。
输入样例:
在这里给出一组输入。例如:
10001
郭靖
13807911234
南昌航空大学
2
101
发电机
80
60
40
80
102
信号发生器
55
70
60
45
MU1234
昌北国际机场
大兴国际机场
2025-04-22
1000
900001
2025-04-22
南昌大学
洪七公
18907912325
北京大学
黄药师
13607912546
输出样例:
在这里给出相应的输出。例如:
客户:郭靖(13807911234)订单信息如下:
航班号:MU1234
订单号:900001
订单日期:2025-04-22
发件人姓名:洪七公
发件人电话:18907912325
发件人地址:南昌大学
收件人姓名:黄药师
收件人电话:13607912546
收件人地址:北京大学
订单总重量(kg):125.0
微信支付金额:3350.0
货物明细如下:
明细编号 货物名称 计费重量 计费费率 应交运费
1 发电机 80.0 25.0 2000.0
2 信号发生器 45.0 30.0 1350.0
思考:
看到这个题目,首先是要求的几个原则:单一职责原则(40%)、里氏代换原则(20%)、开闭原则(20%)、合成复用原则(20%)
然后依据这几个原则去设计。
首先是面向对象设计原则应用:
1.单一职责原则
Good类仅负责货物属性与计费计算,Flight类专注于航班载重管理, OrderProcess类处理订单流程与报表生成,每个类职责明确。
2.里氏代换原则
Customer、Sender、Receiver继承Person并扩展属性(如Customer添加id),子类可替换父类使用而不破坏逻辑。
3.合成复用原则
OrderProcess通过组合Flight、OrderInfo、Customer、Good等类实例,而非继承,体现 “组合优于继承” 的设计思想。
4.开闭原则(部分体现)
费率分段逻辑(getRate方法)通过条件判断实现,若未来新增费率区间需修改代码,可能违背开闭原则,但当前设计已满足题目要求。
然后是实体抽象:
实体类抽象
1.客户与收发件人:抽象出Person基类(包含姓名、电话、地址),通过Customer(客户)、Sender(发件人)、Receiver(收件人)继承,体现 “角色复用” 思路,符合里氏代换原则。
2.货物:Good类封装货物属性(长宽高、重量)和计费逻辑(体积重量计算、费率分段),直接实现文档中 “计费重量取实际重量与体积重量较大者” 的规则。
3.航班与订单:Flight类管理载重限制,OrderInfo与OrderProcess组合处理订单信息和流程,符合 “数据与逻辑分离” 原则。
接着是计费逻辑实现思路:
1.核心算法落地
在Good类中,通过getVolume()计算体积重量(长 × 宽 × 高 ÷6000),chooseVorW()比较体积重量与实际重量,取较大值作为计费重量,完全对应文档示例。
getRate()与money()方法实现分段费率计算:重量 < 20kg 时费率 35 元 /kg,20-50kg 时 30 元 /kg,依此类推,符合文档中的分段函数要求。
2.订单整合计算
OrderProcess类通过getTotalWeight()汇总所有货物的计费重量,calculatePayment()累加单件货物运费,最终生成总金额,满足 “多件货物单独计费” 的需求。
最后是流程控制与用户交互
1.输入输出逻辑
Main类通过Scanner按顺序读取客户信息、货物数量及详情、航班信息、订 单信息,符合题目 “从键盘依次输入” 的要求。
OrderProcess.processOrder()方法格式化输出订单报表和货物明细,包含 航班号、订单日期、收发件人信息及运费详情,与文档要求的报表结构一致。
2.业务规则校验
通过Flight.canCarry()方法检查订单总重量是否超过航班最大载重,若超 过则输出提示信息,确保业务逻辑的正确性。
代码规模:

类图:

复杂度分析:









BUG分析:
公测:
无问题
互测:
无问题
测试方法:
通过PTA上的测试案例以及老师的补充案例来测试程序的正确性。同时,对程序输出结果进行详细记录和分析,观察订单输出是否符合预期。
第二次作业——题目集9
题目:
与题目8类似,但是加入了
1.货物类型分为普通货物、危险货物和加急货物三种
2.支付方式(支付宝支付、微信支付、现金支付)
3.用户分为个人用户和集团用户,其中个人用户可享受订单运费的9折优惠,集团用户可享受订单运费的 8 折优惠。
其他都几乎一样
思考:
对于这题,只是加入了几个可扩展的类:用户、支付方式、货物而已。如果第一次作业已经写出来了,那么这次作业就应该手到擒来。由于上一次作业已经遵循了单一职责原则(40%)、里氏代换原则(20%)、开闭原则(20%)、合成复用原则(20%),所以只需要顺着写就好啦。
首先,我把上次作业的customer类也当做父类了,因为用户分为个人用户和集团用户,两个不同类型的客户继承customer类
然后,由于要选择支付方式,我又新增加了PayWay类来完成支付方式的选择
接着,由于货物也有了类型,所以Good类也有了作为父类,有另外的3个货物类来继承他。
最后,由于不同的客户类型,不同的货物类型,都有不同的金额计算方法,我在
Main类里面进行客户类型,货物类型,支付方式的甄别,并且在最后在OrderProcess类里进行最后的金额计算。
代码规模:

类图:

复杂度分析:
















BUG分析:
公测:
无问题
互测:
无问题
测试方法:
通过PTA上的测试案例以及老师的补充案例来测试程序的正确性。同时,对程序输出结果进行详细记录和分析,观察订单输出是否符合预期。
踩坑心得:
对于这次作业,我觉得比较简单,对比与上次的魔鬼电梯,我觉得完全不是一个级别的。而做这题的让我唯一比较恼火的就是金额的计算。由于李曼有一个规定:
计费重量的确定 空运以实际重量(Gross Weight)和体积重量(Volume Weight)中的较高者作为计费重量。 计算公式: 体积重量(kg) = 货物体积(长×宽×高,单位:厘米)÷ 6000 示例: 若货物实际重量为 80kg,体积为 120cm×80cm×60cm,则:体积重量 = (120×80×60) ÷ 6000 = 96kg 计费重量取 96kg(因 96kg > 80kg)。
我在最后计算金额的时候,总是把实际重量当成计费总量来计算,导致我修改代码修改了2个小时,最后还是在同学的协助下才发现的。这个给我的提示就是看题要认真且仔细。
总结:
这次的两个迭代题让我很好的理解和运用了抽象,多态,继承三大知识点。让我能够熟练的掌握这几个知识点。
课程建议:
本人对课程很满意,没有意见。谢谢老师!
浙公网安备 33010602011771号