PTA8-9航空货运管理系统总结

第8,9次题目集总结

一、前言

题目集8-9均在重点考察类的设计原则,要求符合单一职责、里氏代换、开闭原则、合成复用原则等几大设计原则;两个题目集均为三道题,题目量不大,三道题的算法均较小,只要符合类设计要求,基本上不会出现不符合答案的情况,只要仔细读题,认真理解,细心设计,都能做出来,难度不大。

二、设计与分析
1.第八次题目集航空货运管理系统

题目类设计要求:
程序需要从键盘依次输入填写订单需要提供的信息,然后分别生成订单信息报表及货物明细报表,要求符合面向对象设计原则中的单一职责原则、里氏代换原则、开闭原则以及合成复用原则。

设计类图:

Main类:主要处理信息输入输出,以及创建对象进行运行。

SystemManager类:将SystemManager类进行复用,而不是继承,调用它处理订单的方法,体现合成复用原则,SystemManager类把各个订单分批处理完(虽然此题目只有一个订单hhhhhhh),OrderProcessor类用于处理订单各种信息,进行报表格式化输出。

WechatPay,AliPay两个类:都是实现了PayStyle接口,复写同一个方法pay(),用于同一个订单不同情境下的支付方式,体现里氏代换原则(在定义支付方式时可以用WechatPay或者AliPay类来替换PayStyle类来使用),同时体现了开闭原则(可以对pay()方法的功能进行拓展,对修改关闭)。

Calculator类:单独用于计算运费的计算器,根据货物重量实时计算出对应的价格,也是进行了程序主要的算法。

其他的类:都是用于存储各自的信息,体现单一职责原则。

SourceMonitor代码分析:

image
image

Average complexity(平均复杂度):1.23
Average Block Depth(平均块深度):1.65层
Maximum Complexity(最大复杂度):6.00
Maximum Block Depth(最大块深度):4.00层
Average Statements per Method(每个方法平均语句数量):1.67
Comments(注释占比):9.9%
Classes(类数量):12

经过多次面向对象程序设计题目集的训练,学会了基本的设计思路,初步懂得了该怎么去合理地设计类和方法,再加上此次算法难度不大,因此本次题目代码平均复杂度较小,平均块深度也较小,并且最大复杂度和深度都不大,从而说明了多次题目集训练取得的小小的成果,但是缺点是代码注释占比小,注释总量也不多,说明了写代码的时候还是不太用心去写注释,养成不良好的习惯,日后改善。(下次一定!!!

2.第九次题目集航空货运管理系统

题目类设计要求:
对之前航空货运管理系统程序进行迭代性设计,目重点考核面向对象设计原则中的单一职责原则、里氏代换原则、开闭原则以及合成复用原则、依赖倒转原则。

设计类图:

image

Main类:主要处理信息输入输出,以及创建对象进行运行。

SystemManager类:将SystemManager类进行复用,而不是继承,调用它处理订单的方法,体现合成复用原则,SystemManager类把各个订单分批处理,OrderProcessor类用于处理订单各种信息,进行报表格式化输出。

WechatPay,AliPay,Cash三个类:都是实现了PayStyle接口,复写同一个方法pay(),用于同一个订单不同情境下的支付方式,体现里氏代换原则(在定义支付方式时可以用WechatPay,AliPay,Cash类来替换PayStyle类来使用),同时体现了开闭原则(可以对pay()方法的功能进行拓展,对修改关闭)。

Individual,Corporate类:实现DiscountStyle接口的折扣方法,实现不同的客户有不同的折扣率,是开闭原则和里氏代换的共同体现。

Dangerous,Normal,Expedite类:同上,实现RateStyl接口的费率方法,不同的货物不同的费率,同样是开闭原则和里氏代换的共同体现。

CalculatePrice类:单独用于计算运费的计算器,根据货物类型、重量,客户类型,实时计算出对应的计费重量,计费率,总运费,也是进行了程序主要的算法。

其他的类:都是用于存储各自的信息,体现单一职责原则。

SourceMonitor代码分析:

image
image

Average complexity(平均复杂度):1.57
Average Block Depth(平均块深度):1.88层
Maximum Complexity(最大复杂度):15.00
Maximum Block Depth(最大块深度):5.00层
Average Statements per Method(每个方法平均语句数量):2.02
Comments(注释占比):10.9%
Classes(类数量):20

根据数据分析,此次代码平均复杂度和深度变化与上次相差不大,但是最大深度和复杂度却大了不少,原因有本次的题目加大了算法难度,新增了客户类型,货物类型,支付类型等对计算运费时均匀影响,因此需要分多个类别进行运算,虽然运算算法仍然是weight * discount * rate这样简单的相乘,但是费率和折扣要分多种,特别是货物不同的类型有多个不同的计费费率,因而加大了算法,同时自己代码上也有欠缺,没有采取最佳算法,导致复杂度也提高了。

三、踩坑心得

1.注意题目要求,取体积重量和实际重量的较大者,而并不一定是实际重量的计费。

image

image
2.注意订单有多个,应该创建一个订单容器,用于存储多个订单信息,并将订单容器作为属性通过构造方法来初始化它,以便于后续对多个订单进行信息报表

image

image

image
3.请注意飞机起飞最大载重,一但超过了最大载重将不得起飞,进行错误处理,并且要注意最大载重计的并不是实际重量而是计费重量。

image
4.注意输出格式是控制格式符\t并不是空格。

image

image
5.实现接口方法时不仅要implements接口名称还要@Override复写标志,最重要的是原方法的类型是什么就是什么,参数是怎么样的就是怎么样的,顺序应该一致,类型要统一,连名称都要一样。(tips:后续如果一个接口有多个方法,那么实现它方法的类一定要将所有方法进行复写,不然就是错误)

image

image

6.在第二次迭代的航空运输管理系统中,有客户和货物类型选择,从而构成不同的折扣率和计费率,因而可根据输入的内容创建不同的对象,其实只有将输入的两种类型保存为字符串型,switch,case是可以将字符串作为选项的。

image

7.假如你真按我上面建议你做的,把用户或者货物类型存储为字符串,那么恭喜你迎来了第二个坑。还是在这,因为用户输入的字符串是不确定的,所以一旦你字符串不匹配,即使有default,但是在switch之外的你用discoutStyle进行运算,编译器就会默认你可能没有考虑到字符串不匹配的情况,那么就没有进行初始化DiscountStyle,它仍然为null,不能调用它的方法来获取折扣,所以一开始(switch进行之前)你就应该默认一个初始化的对象,在匹配到字符串后再进行修改。

image

8.我不确定是出题老师出错了,还是我理解错了,为什么应交运费和支付总额不一样,难度每个货物应交费用加起来不应该是支付总额吗?所以为什么应交费用是没打折前的价格。

image

四、改进建议

1.代码中虽有少量类注释(如 “单一职责原则”),但关键方法(如CalculatePrice.calculateWeight的体积重量计算逻辑)、复杂条件判断(如费率阶梯规则)缺乏注释说明。

2.OrderProcessor类不仅负责订单处理逻辑(如运费计算、载重校验),还承担了输出格式化展示的职责(如打印订单明细、支付信息)。这使得单一职责原则贯彻不彻底,建议将业务逻辑与输出逻辑分离。

3.在OrderProcessor的processOrder方法中,遍历货物列表时每次循环都重新创建CalculatePrice实例,且在计算总费用后,又再次循环创建实例打印明细,在首次遍历货物时,将每个货物的计算结果(如计费重量、费用)暂存到一个中间对象,并存储到列表中,后续打印明细时直接读取中间结果,避免重复计算。

4.其实属性名称尽量不要太长(不然容易超过代码长度限制hh),然后在每次使用该属性的时候直接选中提示框里你需要的属性(大部分新版本编译器都有这样的功能),非常有助于你快速准确的写好代码,也不会出现一些非常低级的错误。

5.SystemManager通过构造方法注入OrderManager,符合合成复用原则,但可进一步抽象高层模块(如SystemManager)与低层模块(如OrderManager)的依赖关系,通过接口解耦,提升系统扩展性。

五、总结

一、学习到的内容:
1. 单一职责原则:明确类的功能边界
每个类应专注单一职责(如Customer管理客户信息、Cargo管理货物属性),避免功能混杂。拆分职责可降低复杂度,提升代码可维护性,例如将订单处理与输出逻辑分离为独立类。

2. 开闭原则:对扩展开放,对修改关闭
通过接口抽象行为(如PayStyle支付方式、RateStyle费率计算),新增功能时只需扩展实现类,而非修改原有代码。例如新增 “现金支付” 时,仅需实现接口即可。

3. 里氏代换原则:子类可替换父类
定义抽象接口(如DiscountStyle),确保子类(Individual/Corporate)遵循父类的方法。子类重写方法时保持行为兼容,使高层模块(如CalculatePrice)可透明使用子类实例,增强系统灵活性。

4. 合成复用原则:优先使用组合而非继承
通过组合关系(如Order包含Customer/Flight实例)构建系统,而非继承。例如SystemManager持有OrderManager实例,通过委托实现功能,降低类间耦合,提升复用性。

5. 接口隔离与依赖倒置:抽象层决定系统架构
将变化点抽象为接口(如支付、费率、折扣),高层模块依赖抽象而非具体实现。例如OrderProcessor依赖PayStyle接口,而非具体支付类,使系统更易适应需求变化。

二、仍需学习和提升的地方:

  1. 设计原则的灵活应用深度不足:对开闭原则的理解停留在基础接口实现,复杂业务场景下(如多层策略组合)的抽象设计能力待提升。

  2. 参数校验与异常处理的完整性:未全面覆盖空指针、非法输入等边界情况,需系统学习异常处理体系(如自定义异常、断言机制)。

  3. 代码复用性的优化策略:部分逻辑(如运费计算)存在重复实例化,缺乏对工具类、缓存机制的应用,需掌握更高效的复用技巧。

  4. 类间依赖关系的精细化管理:组合关系的层级控制不够清晰(如Order嵌套多层对象),需学习依赖注入(DI)或设计模式降低耦合度。

三、建议与意见:

1.希望老师能多提供一些好的学习资源和好的学习工具,帮助大家更系统、更全面地学习java课程。

2.希望老师们能够多教大家一些能与当今行业相接轨的知识和热点,让我们能更好的融入到行业当中,所做的内容与行业所关心的息息相关。

3.希望老师可以偶尔演示一下该如何分析一下比较复杂的项目,该从哪起手,怎么设计类与方法,实操一下看看行业里的程序员是如何分析问题的。

posted @ 2025-05-21 20:30  北纬25度  阅读(41)  评论(0)    收藏  举报