OOUnitOneSummary

程序分析

第一次作业

思路:

  第一次作业只涉及多项式的求导,所以结构比较简单。我借鉴课上的经验,用一个Term类来处理系数和幂次数,然后再用一个Map结构的TermMap类来存储整个表达式,并通过TermMap进行表达式的合并化简,最后对于TermMap中每一项进行求导,再通过加减字符连接输出出来。

  由于第一次作业中保证输入的表达式均为正确格式,所以我通过正则表达式进行了化简,删掉空白字符,并通过正则表达式找到不在乘号之后的加减号进行项的拆分,使我后面的处理简单了不少。

第一次作业的UML图如下:

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

其中,MainClass为主类,除main外只有一个simplify方法通过正则表达式对输入进行化简。

Term中两个BigInteger变量分别存储系数和幂次,TermMap用于存储整个表达式的各项并进行求导以及初步化简操作,以及通过重写toString方法生成输出结果。

优点:代码简洁明了,可以很快定义bug的位置,而且进行了去0以及合并同类项初步的化简工作。

缺点:没有领悟到面向对象的真谛,写的过于面向过程,而且对于没有系数以及幂次的x处理的不好,导致额外多写了很多方法,导致代码显得十分臃肿

度量分析:

 

 

 

 

 

   由图可以看出,Term的toString和addTerm的复杂度极高,二者无一不是因为里面存在过多的if-else语句,前者是为了进行优化,尽量减少输出长度;而后者是由于我将太多的内容都交给addTerm来处理,以及进行了大量的符号判断所致。

BUG分析:

  强测数据点全部通过,互测被hack9次,但只有一处bug,由于代码写的十分匆忙,没有认真读题,导致我在simplify方法中将-x**2这种偶数幂次化简为x**2导致出错,是一个十分低级的错误。

第二次作业:

思路:

  由于我第一次的整体架构无法处理涵盖括号的嵌套函数,在经过反复挣扎后进行了重写。我借鉴了作业的提示思路,用表达式树进行处理,首先对每种函数以及运算符都写一个类,并写出其求导方法,最后递归求导。由于数据保证合法性,我还是先对数据进行化简,然后用parse将化简后的输入数据转化为后缀表达式,进而转化成表达式树,递归求导后用toString方法进行递归输出。

 

 

 其中,MainClass为主类,simplify为化简方法,expresstionTree将后缀表达式转化为表达式树。

parse是对输入字符串进行分析的方法,首先将项剥离出来构造Term,然后用一个Objecrt的ArrayLis将其存储,形成(Term +/- Term)* Term ... 的形式,然后将改造后的中缀表达式转化为后缀表达式,并返回后缀的ArrayList。

Term为所有函数类型和函数组成的父类,其中用到类似工厂方法生成不同的子类,以及一个待实现的求导方法。(编写代码时不太理解工厂方法以及接口实现等,写的十分粗糙)

Term子类包括Constant(常数)、Power(幂函数)、Trigonometric(三角函数)三个函数类型以及PlusMinus(加减)和Multiply(乘法)两个函数组合方法,其内部分别实现了递归求导以及递归的toString。

优点:思路比较清晰,并初步将学到的继承等知识运用到代码中。

缺点:生成表达式树的过程比较复杂,没有用到递归下降或正则表达式等工具,而且过于面向过程,面向对象的思维不够。

度量分析:

 

 

 

 

 

 由图中可以看出,复杂度较高的为parse类中的parse方法和postfix方法,以及加减、乘法的toString方法,前者的转化必不可少的需要许多条件判断语句,我暂时没有想到很完美的解决办法,后者还是因为优化的过程中需要对0/1等特殊值进行特殊判断。

从UML图也可以看出,第二次代码的耦合度十分高,这也是代码结构复杂,难以察觉、修改bug的罪魁祸首之一。

 BUG分析:

  强测数据中WA了一个点,互测被hack34次,但出现错误的数据的原因只有一个问题,出现在我在优化的过程中,对于加减法toString优化时,在删除多余括号以及判断负号的过程中逻辑混乱导致输出错误。

第三次作业:

思路:

  第三次作业与第二次作业极为相似,只是多了格式检查以及三角函数的嵌套,因此我只是在整个代码的最前方增加了格式检查,并对三角函数进行了修改,将其做成可以嵌套的形式,并在求导时增加递归求导,当然,还要对parse分析方法进行修改,使其可以处理嵌套后的三角函数。

UML图如下:

 

 

 为了节约时间,其中绝大部分都未做改动,如上文思路所说,只是增加了FormatCheck类以及修改三角函数类,其中FormatCheck类主要通过正则表达式来实现,为了简化正则表达式,我用括号代替了表达式项,用[]代替三角函数项,然后每次遇到表达式项或三角函数项时进行递归判断是否合法。

度量分析:

  

   由图可以看出,parse和postfix方法以及toString仍然复杂度较高,在此就不做赘述,此外,FormatCheck的checkPoly和checkTerm两个方法复杂度也过高,究其原因也是因为if-else结构使用较多。

 由于第三次作业基本继承了第二次作业的模板,因此和第二次作业暴露的问题基本相同,也存在耦合度过高的问题。

BUG分析:

   强测wa了两个点,互测被hack1次,可能是由于颁布恶意hack的惩罚机制,这次被hack少了很多,主要问题还是出在格式问题上,由于我看错数据范围,以为不会出现巨大指数问题,导致只使用了int进行格式检查,出现exception,此外就是输出的格式也有一处细节问题。

找他人BUG策略

  我主要通过自己在测试过程中构造的一些极端易错数据来进行测试,而由于不知道什么原因,我在下载代码后无法在我的idea中运行,所以很多情况下只是提交一些自己构造和记录的易错数据进行hack。

此外,虽然无法运行,但我也尝试通过阅读别人的代码来找出些许错误,例如,我在编写代码时修改了一个bug:由于递归调用toString过多,容易超时,在我阅读的代码里面有人有同样的问题,我便构造了特定数据成功hack。

重构经历总结

  由于我第二次的思路与第一次完全不同,第一次的作业无法实现第二次的功能,因此我直接进行了重写,而第三次则是在第二次作业上稍作修改便成功通过中测,因此在整个第一单元的过程中我只有重写和直接迭代,并没有进行重构。

心得体会

  在第一单元的学习中,我初步理解了面向对象的思想,从最开始的面向过程逐渐开始蜕变。但与此同时,我认识到自己有非常大的问题,首先是细节问题,两次都因为课题介绍看的不完整而产生了小bug,只能眼睁睁看着自己被hack;而且我感觉自己的架构设计的并不是很好,耦合度很高,有些结构里面十分复杂,亟待修改;此外,我找别人bug的效率很低,需要多多学习增长hack能力;除此之外为了完成任务,我可能写出了很多邪门歪道的代码,与面向对象的思想严重不符,而且我的优化也做的远远不够,性能分几乎流失殆尽。

  无论如何,第一单元也是成功地被我熬了下来,虽然在这三周遇到困难无数,但我感觉自己的能力和心态也受到了锤炼与提升,在新的单元我会努力纠正第一单元暴露出来的问题,在完成任务的基础上更多地想想如何优化,提高自己的编程能力。

 

 

posted @ 2021-03-30 01:52  .Aatrox  阅读(67)  评论(1编辑  收藏  举报