OO第一单元总结

基于度量分析程序结构

第一次作业

第一次作业只涉及到常数因子和幂函数,求导也很简单,但是也因为是第一次作业,完全没考虑到要在此基础上迭代,我在设计时只考虑了怎么能让本次作业写起来更简单,架构很简单,可扩展性差。本次作业类图如下。

我这次只设计了两个类,Main和Item。整个过程也是面向过程的思维方法。我采取的方法是一次性将数据读入,,然后通过替换分割得到单项式\(c*x^i\),Item这个类只是便于存单项式\(c*x^i\),有求导方法,返回值仍是一个Item。compareTo方法是比较系数大小,将输入一次性拆成单项式后用ArrayList存起来,指数相同的合并,排序后输出,排序将系数大的先输出。

第一次作业复杂度如下

class Ocavg OCmax WMC
Item 1.88 8 15
Main 4.60 10 23
Total 38
Average 2.92 9.00 19.00

可以看出,虽然第一次作业简单,但是我设计的并不是很合理,所有字符串的输入处理拆项和化简输出都放在Main里,导致Main异常臃肿,从输入到拆分得到Item的过程都在Main中的simplify方法中完成,所以simplify方法复杂度格外高。另外为使输出简单,Item的ToString方法中用了很多条件语句对系数指数为0或1的特殊情况进行判断。

本次作业架构的优点是化简简单(至少对我自己来说这样写简单),但是缺点也非常明显,不合理的架构和可扩展性差导致第二次作业全部推倒重构。

第二次作业

第二次作业增加了三角函数,表达式因子,果断选择了重构,舍弃了原来的单项式因子,类图如下

Factor是所有因子的父类,Constant是常数,Pow是幂函数,Sin和Cos是三角函数,Poly是因子相乘的项,Expression是表达式(因子),它们都继承Factor。我没有写求导的接口,而是给所有类都写了一个求导的方法。

复杂度如下

这次增加了很多类,但是我获取项或因子的方法依然采取了替换字符串中的运算符然后split分割。我采取的是识别表达式中不在括号中的+-或*来分割得到项或因子,需要遍历字符串然后多重条件语句嵌套判断是否是分割项或因子的操作符,这就导致涉及到取项及项求导的方法控制结构嵌套非常多,比如getPolys和Poly中的方法。

另外,由于我的表达式和表达式因子都是Expression类,所以出现了循环嵌套的问题,读入数据后,我会先把整行作为一个表达式,丢进Expression中处理,然后拆成若干个Poly,Poly里再将项拆成因子,如果是表达式因子,再作为Expression处理,所以Expression和Poly可能会互相调用多次,我觉得这是我设计中不好的一点。这次作业相比第一次难度大了很多,所以为了保证正确性没有做任何优化(虽然最后依然错了不少)。优点是相比第一次作业进步很大,也可以在此基础上加功能。

第三次作业

第三次作业在三角函数中增加表达式因子并不困难,我主要是在格式判断上卡了很久。本次作业类图如下

第三次作业基本沿用了第二次作业的架构,只是在三角函数类的构造和求导方法上做了改动,主函数中增加了格式判断。这次作业时间基本上都花在了格式判断上。因为担心出错不想在各种因子类里改动,所以我选择了读入一行数据后在Main中先进行格式判断,若合法再拆解表达式和求导。方法复杂度如下

这次数据几乎一半都红了,因为第二次作业基本都保留下来了,所以Poly和Expression里的方法太长太复杂等问题也保留下来了,另外,Main里增加了很多为判定格式的方法,有一半复杂度都过高。主要原因是因为我做格式判断时采取的方法是:先整行读入,然后通过遍历字符串的方式依次检查是否是非法字符,空格非法,指数非法,三角函数非法等问题,一旦检测到有错误即非法,而在这些方法里都用了相当多的条件嵌套和循环语句。

我自认为这样进行格式判断并不是一个好方法,而且我是通过找错误来判定是否合法,这样就导致必然会出现本来不合法但是判定不出来的情况。但是优点是不会破坏第二次作业基础上的求导正确性,最后强测证明也确实如此,没有求导错误只有格式判断错误。

自己程序的bug

第一次作业

第一次作业在强测中被发现一个bug,互测中未测出bug,出现bug的原因在于对于\(0*x^i\)的项,虽然都是0,但是由于存的指数不同,在我的程序中无法合并,而在输出时我忽略了结果为0的项,导致类似\(0*x**1+0*x**2\)无法输出结果。对比分析出现了bug的方法和未出现bug的方法,我发现我的bug正是出现在最复杂的方法simplify中,其他较简单的方法没有出现bug。

第二次作业

第二次作业在强测和互测中都错了不少,但是实际上是一个问题,在处理表达式因子时忽略了其前的负号,出问题的依然是最复杂的Expression中的取项方法,方法写的过长再加上对符号和括号等进行了很多特殊判断,所以导致疏漏某些情况,出现bug。归根结底我认为是我方法写的不合理,有的写得过长过于复杂,本可以按功能拆分成更不易出错的方法。

第三次作业

第三次作业在强测中发现了几个格式判断错误的bug,这个自己在写的时候已经想到了我这种写法必然会出格式判断的问题,但是也并没有想到其他很好的方法,强测数据中出现了两种我没有考虑到的格式错误的情况,bug修复阶段我增加了格式判断的条件,但是感觉依然有疏漏,只是没有检测出来罢了。

发现别人的bug采用的策略

因为不会写自动构造数据的程序,所以我的测试数据都是自己手动构造的,或者来源于讨论区群聊等其他人提供的数据。一般我采用的方法是先测我自己出现过bug的数据,这种情况命中机率较高,然后尝试其他同学提过的数据,最后自己手动构造能想到的所有数据。

重构经历总结

第一单元的作业中我重构了一次,第一次作业考虑得过于简单再加上第二次作业变化比较大,所以第二次作业就重构了。因为第二次作业一出来就知道原来的完全用不了要重构,所以没有在要不要重构上纠结,直接丢弃了。从类图和方法复杂度上可以看出第二次作业相比第一次变化非常大。第二次作业设计相对合理一些,可以满足第三次作业的要求,于是第三次作业做起来相对轻松了许多。

第二次作业重构的时候写的非常痛苦,一直从表达式因子里绕不出来,周五晚上痛苦重构的时候甚至觉得自己会没办法完成这一次作业。好在最后比预计的最坏情况好一些,还是完成了,但是因为时间紧任务量大(相比第一次而言)出现了很多bug。而且重构后的类中的方法非常多且长,debug也比较困难。但是当时想到了第三次作业一定会出现三角函数里有表达式,重构完思考了一下第三次作业该怎么加功能,尽管考虑得不是很全面,但好歹第三次不用重构了。

心得体会

总体说来这三周作业写得非常(痛苦)充实。第二周作业在周五晚上开始重构时,艰难写完后交上去错了一半,然后根据公开的数据点慢慢修改,改完公开数据点后大约还有三四个,然后通过自行构造各种数据以及询问同学,每次以为改好结果交上去只多通过了一个点,心态崩溃。第二天早上继续Debug,终于在中午前过了中测。然后开始了一天痛苦优化阶段,然而优化失败,在提交8次后最终在周日晚上截止上交了未优化的版本。虽然过程痛苦但无疑是有收获的。

  • 合理架构很重要,不要为了偷懒不愿意重构。
  • 多与同学交流,一个人的思维总是有局限的,如果是自己手动构造数据很难测出自己的bug。
  • 尝试学习搭建自动评测工具。每次艰难写完后手动构造数据然后肉眼判定结果的正确性效率实在太低,多次想学写自动评测的工具,但是每次在截止时间前才完成作业,然后互测修复bug后又是下一次作业,所以一拖再拖。
posted @ 2021-03-29 10:45  长夜将尽  阅读(83)  评论(0)    收藏  举报