南昌航空大学面向对象第二轮作业总结

面向对象第二轮作业总结

前言

关于题量

第二轮只有两次pta作业,第一次是雨刷系统,点面问题,航空货运管理系统,第二次是魔方问题,点面问题再重构,航空货运管理系统的扩展。题量并不多。

关于知识点

第一次的点面问题再上一轮中有写过,这次是对其进行重构,实现继承和多态。

雨刷系统在上一轮中也写过,再这次中对其进行重构,添接口,实现继承和多态。

航空货运管理系统是考验类设计,要合理的分离出类,什么类做成抽象类,怎么实现多态。

魔方问题也是实现继承和多态,

点面问题再重构是考验容器类的使用,

航空货运系统的扩展添加了接口,新增了客户的类别和货物的类别。考验再添加内容是是否能够符合开闭原则

关于难度

这两次的作业的逻辑并不难,难的是类的设计,需要仔细思考怎么把航空货运拆分成多个类,类与类之间的关系是怎么样子的,并且要合理,这是一个难点,因为拆分好了后面才能更好的扩展不需要修改源码。

设计与分析

航空货运管理系统(类设计)

类图分析

根据航空公司提供的信息和职责的划分我拆分出了货物类,订单类,收发人类,运送信息类,客户类,航班信息类,支付类,控制类

货物类为一个抽象类,继承了一个矩形货物类,考虑到后面货运时会出现不规则货物,所以将其作为抽象类。

收件人和发件人因为属性完全一致,所以我将其作为一个类。

在订单中需要有一个运送信息,需要包含收件人和发件人,所以我把运送信息单独作为一个类,把收件人和发件人作为属性嵌套进其中。

一个货运必须要有订单,所以我拆分出来了一个订单类,运送信息与订单关系紧密所以我将其作为属性放入其中。一个订单中可能会不止有一个货物,所以我做了一个LinkedList来放货物。

客户并不需要参与到货运中去只负责下单,所以我把客户单独作为一个类,因为认为客户不需要扩展,所以并没有将其作为抽象类。

根据提供的信息航班信息需要单独做成一个类,将航班相关的信息放入其中。

由于有多种支付方式,所以将其作为抽象类,派生出支付宝和现金支付类。

这些类并没有关联,所以做了一个控制类来调用这些类将他们关联起来。但考虑到费率的计算方式可能会变,所以将控制类做成了抽象类,避免后面修改费率是需要修改源码。

SourceMonitor代码分析

  • 函数复杂度
    最大复杂度为5,在Agent1中为了判断费率需要写多个if-else所以导致最大复杂度变为5,但是代码并不复杂。if-else写多了结构可能不太清晰,后续可以考虑换成switch来写。
    平均深度并不大,因为只有几个地方得复杂度达到四和五、但代码都不复杂,其余并没有太多分支语句。
点击查看代码

  • 代码深度
    表上的代码最大深度为3,但是我仔细和代码比对了一下,嵌套层级为三的都是只有一级,只是内部调用了其他方法。对于第一轮的电梯系统来说深度有明显的下降。
点击查看数据和代码对比

其中第三个数据为代码深度




  • 代码注释率
    代码注释率为9.9,除了get-set方法没有注释外,其他方法基本都有注释。每个类中的属性也都有注释。能够较为容易的读懂,修改也好修改,后续在对航空货运系统进行就体现出来了,因为隔了一段时间所以会有所遗忘,对着注释看能提高我的阅读效率,也更好修改。

  • 类中的方法数

平均下来有大概7个,这说明每个类中的方法拆分的较为合理,做到了每个方法只做一个事。

  • 每个方法的平均语句

因为逻辑较为简单,所以每个方法并不需要很多语句,所以就显得相对降低。

  • 心得:拆分类时要根据职责划分,要做到符合单一职责原则。在拆分完之后写代码时可以先对最底层的类写起,例如收件人发件人,客户这种没有子类的一层一层的往上写。

航空货运系统(继承和多态)

类图分析

航空快递以速度快、安全性高成为急件或贵重物品的首选,所以本次作业是基于此种情况对上一次pta写的航空货运系统进行扩展。

首先需要扩展的就是费率,由于需要运送的货物类型的不同会有不同的费率计算方式,因为第一次我已经将获取费率作为抽象方法放在了控制类中,本来不需要源码进行修改,但后续我觉得把获取费率做成接口会更好,所以把他从抽象类拿出来做成接口,再由抽象类实现,到每个子类中去复写。

此外还新增了客户类型,最开始我是将客户类型作为一个属性放在客户类的内部,但是后面看到提示才使用继承将不同的客户作为客户类的子类。

对于不同的客户类型有不同的则扣,我把获取折扣率的方法作为了一个接口,由客户类实现,再到每个子类中去复写。

本次新增了现金支付类,直接继承支付类进行扩展,并没有修改源码。

SourceMonitor代码分析

  • 函数复杂度
    这次的函数复杂度达到了12,因为在创建类的时候需要进行很多判断,所以写了很多if-else语句,例如在创建客户类是需要判断是什么类型的客户,支付类的创建也需要进行判断,所以就导致复杂度相较于上一次明显提高,对于这种需要写多个if-else来选择类的创建方式可以替换为简单工厂模式,这样子就可以避免在main方法中复杂度过高的情况,但可能会不太符合开闭原则
点击查看图片

  • 代码深度
    代码深度还是3,因为只是将一些方法做成接口和多继承了一些子类,所以并代码深度并没有增加,也是和第一次一样的问题,内部嵌套层级为1却显示为3,可能是算上了调用方法的层级,总体来说最大的嵌套层级为1,这说明方法拆分的还是较为合理的,逻辑比较清晰。

  • 代码注释率
    代码注释率稍微将低了一点为=9.5=,因为多继承了一些子类,在子类中并没有在去重复写注释所以导致注释率会有所下降。总的来看代码注释率还是够的,能够帮助快速阅读。

  • 类中的方法数和每个方法的平均语句
    因为并没有太大改动,所以这些数据并无太大偏差,所以再次就不再过多赘述。

踩坑心得

这次踩的坑是主观因素太强了,在航空货运中有体积重量实际重量,在计费时是取大一个。输出一个总重量时,我直接默认为实际重量,测试用例的答案用实际重量和计费重量又刚好相同,所以直接忽视了,后续排查也没排查出是什么原因,经过同学提醒才恍然大悟,所以需求分析真的很重要,在这上面一但出错就是做无用功。

此外就是对面向对象的设计原则理解并不透彻,在后续需要扩展时我第一时间想到的是直接把客户类型作为一个属性而不是将其抽象出来,修改属性就需要进行大规模的改动,而要是将其作为抽象类在进行继承的话就可以省下很多功夫,后续在需要扩展时也就不需要改源码了。

改进建议

  • 第一次类的设计还是需要改进的,从第二次的新增需求可以看出一开始的客户类的设计还是不合理的,没有考虑到客户的类型。在第二次进行扩展的时候就需要修改源码了。

  • 可以把收件人和分开来写,直接把收发作为抽象类直接继承下来。

  • 在创建类时可以使用简单工厂模式,这样可以减少主方法里的复杂度。

  • 因为输出过长,所以可以在Main类里把输出单独做成一个方法这样就不会显得主方法看起来冗余。

总结

通过这两次的习题我感受到了多态和继承的好处和强大,可以省下很多功夫。使用多态就不必区分每个子类了,直接使用抽象类对new使用上转型就可以省去很多麻烦,特别是配合简单工厂模式使用,会显得代码更加干练,也更清晰。并且使用继承和多态非常契合OCP(开闭原则),只要再写一个子类就可以,这样即使出错了也不用检查之前的代码,出现BUG的时候更加容易排查。

其次是类设计,类设计合理做起来事半功倍。像在上文提到的,在第一次设计客户类的时候并没有将其做成抽象类,然而在后续扩展时就又需要修改源码,这就会牵一发而动全身,其他地方也就需要跟着修改,这就事倍功半了。同时也要做好需求分析,做好需求分析才能更好的进行类设计。

此外还需要加深对面向对象设计原则的理解,这次就没有很好符合OCP,但是通过这次错误加深了对OCP的理解,对可能需要扩展的地方尽可能得用继承和多态来写,即使麻烦一点,但在后续扩展中能省下很多麻烦,不能仅局限眼前。

posted @ 2025-05-22 20:14  0486  阅读(35)  评论(0)    收藏  举报