前三次作业总结
前三次作业总结
前言
前三次作业集是一个迭代式作业,从第一次基础的装载货物并判断是否超载,到第二次多货舱管理与重量排序装载,以及加入了货舱行列和最大业载重量等条件,而最终的第三次迭代作业则引入了乘客重量与力臂力矩以及重心权重平衡。
这三次OO作业难度和复杂度依次上升,结合了基础的输入输出,动态数组,多货仓管理,简单排序,以及类与对象有关的知识点,为今后面向对象的学习打下了良好的基础。
第一次作业
这次的的作业题目要求仅仅只有将货物降序输出,以及将货物总重量与航班最大载重量相比较并输出是否在安全范围内。总体来说这次作业相较于后两次迭代作业来说是比较简单的,因为他没有复杂的类间关系,即使完全依照SRP原则来设计,类的数量也不算多。
本次作业共设计了六个类,其之间的关系如图所示:

Cargo和Flight两个类仅包含其基本属性与简单的getter和setter方法,无复杂方法;功能型的方法都放在了LoadManifest,CargoSorter,WeightAbout这三个类中;而主类Main则负责输入,流程编排和输出。
这其中有一个点就是在刚开始设计的时候我原本是想将除Cargo和Flight以外的其他类内的所有方法都放进LoadManifest,但因考虑这不符合SRP原则,于是将货物排序以及货物重量有关计算另分到了CargoSorter和WeightAbout中,但缺点是这三个类间没有直接的联系,实际使用时需在Main中手动调用。
到此,第一次作业的功能性要求基本达标,用户输入航班最大载重,货物件数,并循环输入货物名称与重量;而程序调用CargoSorter中的方法对用户输入的货物进行降序排序输出,同时调用WeightAbout中的方法累加货物重量,并将其与航班最大载重相比较判断其是否超载。
接下来是对第一次作业中类与方法的复杂度分析,下面是第一次作业的生成报表内容:

可见其中复杂度最高的便是CargoSorter中的sortCargo()方法,主要原因题目中限制了list.sort()方法的使用(其实我也不会),所以只能使用基础的选择排序将货物进行排序,在未来深入学习后定能解决此等问题。
第二次作业
本次作业在第一次作业的基础上进行了迭代,在原有的一个货舱的基础上又增加了一个货舱类,货物增加属于哪个货舱的属性,并且按照货物的货舱属性将货物装载进相应的货舱,再分别按降序后输出,并分别判断货仓是否超载,以及对最大业载数的判断。
本次作业相较于上次新增加了货仓类以及位置类,其之间的关系如图所示:

本次作业的业务逻辑与上一次差别不大,都是排序输出加上重量判断,不同的是现在的数据不能直接在主方法里面用动态数组进行存储排序输出,而是要将货物的存储和管理职责下放到专门的货舱类中,体现了SRP原则以及面向对象的封装性。
这次的题目要求相比于上次就复杂得多,多了很多类及其内部的方法的要求但这也有一个好处就是使我们类的设计,类与类之间的关系,以及对方法的调用更加清晰明了,节省了设计的时间。
但相应的,类的复杂度也有所上升,报表内容如图所示:

不难发现,这次作业无论是类的数量还是其内部方法的数量都有明显的提升,其中还存在在业务操作中未被使用的类,如Position类。根据题目要求这是需要设计的类,而却对其没有实际的有效操作。我觉得这个应该是为了后面的迭代作业提前铺好的路(但后面好像也没用到?)。
这次的题目新增了检验整数与浮点数范围的范围校验类InputValidator,但这个校验是对输出数据进行校验,依旧未考虑数据鲁棒性,但也已经有了后续对输入进行判断的雏形。并且在这次的作业中我已经初步认识到哪些职责应该从main中剥离,以及如何正确地封装数据。
第三次作业
本次迭代的最终战役,第三次迭代作业,本次迭代在要求上新增四个类,实际在新增后达到了十一个类,但鉴于这次完全在V2的基础上迭代,而不是像V1到V2那样删改了几个类,V3是在V2原有类与方法不进行删除的情况下进行修改。这期间的时间间隔使得我要重新去理解我写的类与方法及其之间的关系,这使我认识到给自己的代码标上注释的重要性。
本次作业对数据的鲁棒性有了要求,需要判断我们的输入是否符合要求,类间关系如图:

本次作业的重点是计算以及判断,在这次的作业中,系统需要根据输入的数据进行运算得到其总重,力臂力矩,实际重心及其百分比,并最终通过其重心百分比所处区间判断飞机飞行是否安全。
就我而言,这次作业有一个较大的难题,就是题目中的这句话“与 Flight 是依赖关系。该类不应有 Flight 的成员变量,必须将 Flight 对象作为 generateLoadSheet 方法的参数传入”,在设计这个方法时我不确定该返回什么类型的数据。首先想到的便是不返回,直接在该方法内输出,但这不符合题目中要求的纯计算工具类。经过思考后我决定新建一个存储数据的类,但这又引出了后面的问题:我没有在主方法中初始化该类,导致输出的数据始终为零,经多番查找才发现问题。
第二个问题是验证数据,对浮点数的判断还好,毕竟只要判断输入的是浮点数并且为非负值就行,但在对整型数进行判断时,题目要求的是判断整型数是否在一个区间内,可一些整型数据的范围要求只是大于零就行,于是我选择了暴力解法:将上限定为999999999,希望在之后的学习中能解决这类问题。
而依据SourceMontor生成的报表分析(如图)

本次作业类的复杂度特别高,实际上是我在这方面的不足,对代码的优化知之甚少,甚至可以说是完全没有优化,这次是为了完成题目中的要求,但这也体现了我在这方面的欠缺。而且在写代码的时候多次遇到不清楚的功能,比如题目要求的遇到非法输入直接终止程序运行,经学习后才得知exit()方法。
依据报表分析,本次迭代作业代码结构清晰度中等,而复杂度控制较弱,唯一的优点可能就是业务逻辑还算完善。
坑与测试

看到测试点报这个心已经凉了半截了,除上面在过程中出现的问题,这次迭代作业的测试也是一大坑点,比如第一次作业中的排序超载测试,不能使用冒泡排序而是要使用选择排序;又比如第三次作业的装载前舱货物数量输入数据范围非法测试,题目要求的是范围是0到最大件数,而实际代码所需的是1到最大件数,这些也算是在完成过程中出现的坑了。当然,这些问题的解决少不了我的同学们的点拨,在这里对帮助过我的同学们表示感谢。
目标与改进
这次作业基本业务需求虽然达标,但仍然存在许多的问题与不足,在对生成的报表进行分析后发现Main类逐渐膨胀,主要原因是将许多功能放进了Main类中,这影响了可读性和可维护性,可以将Main进行拆分以此来改进;有些类的封装性不够强,这可能会导致数据被篡改,日后将通过遵循最小暴露原则,用行为代替数据访问等方法进行改进。
总结与展望
通过这三次迭代,我深刻体会到增量开发与需求变更对软件架构的影响。从简单的货物列表输出,到多货舱定向装载,再到重心安全评估,每一次迭代都融入了新的知识,并使我们对上次迭代的功能性与可扩展性进行审视。收获主要体现在初步建立了封装的意识,并且了解到了单一职责的重要性以及输入校验的必要性。
在今后的学习中,我的方向主要是对设计模式进行学习,比如桥接模式、简单工厂模式、建造者模式等。以及对代码进行优化的能力,减少代码复杂度以及更深入的学习面向对象程序设计。
希望今后的学习能够学有所成,享受痛并快乐着的OO学习。
浙公网安备 33010602011771号