概述:
面向对象第一单元的作业是多项式求导,从第一次的简单多项式,到第二次的带有sin和cos的多项式,到第三次的带有嵌套的多项式。从本单元的作业中,我初步了解了面向对象程序架构的基本思想,同时也学习到了一些常用工具,如正则表达式以及java中一些基本库的使用。
一、程序分析
第一次作业
1、思路
第一次作业输入格式较为简单,仅含有幂函数和常数项。解决思路也比较简单,即使用正则表达式辅助将项分开,对每项内部进行分析,得到各项的系数和指数。求导时按指数分类讨论。对于结果的同类项合并,使用一个以指数为key的Hashmap:若表中含有当前指数的项,则合并系数。最后遍历Hashmap输出结果。
2、度量分析
第一次作业我主要写了两个类,主类Main负责输入的一些预处理,Item类负责对每项进一步解析,完成得到系数指数和求导的功能。这里我还是有一些面向过程的思想,预处理不应该在入口中进行而应该单独创建一个类来管理。
第一次作业的代码iv(G)和v(G)较高,说明我的程序高内聚且内部结构复杂,这说明在模块功能内部的实现中还有面向过程的思想,缺少模块的功能分类。
第二次作业
1、思路
第二次作业的输入在第一次作业的基础上多了两种三角函数,但是整体的解决思路仍是不变。即先预处理,再使用+-号分割出每一项,在每一项中再使用*号分割出每一个因子进行解析,解析过后利用乘法法则进行求导。对于求导结果的合并,我们可以把每一项看做是一个三元组<a,b,c>,其中abc分别是x、sin(x)、cos(x)的指数,将这个三元组作为Hashmap的key,剩下的就和第一次作业相同了。
2、度量分析
第二次作业我写了三个类,Main类负责预处理和程序入口,Term类对项进行解析并进行求导操作,IndexKey类是我自己写的作为Hashmap的key的类,重写了equals()和Hashcode()方法。
第二次作业整体结构上还是继承了第一次作业,我认为在输出那里逻辑很复杂,结构没有设计好,为了通过格式检查把一个函数分成三部分,结果结构化程度仍然很高,最终BUG也是出现在这个部分。
第三次作业
1、思路
第三次作业在第二次作业的基础上允许嵌套,即表达式项作为因子和三角函数的自变量存在。由于不知道嵌套的深度,一个显而易见的思路就是使用递归处理。在本次作业中我建立了一个专门用来管理操作的类Str,里面有对表达式解析的方法可以被递归调用。对表达式的解析按照指导书的方法构造树形结构,所有基本项如三角函数、幂函数、常数,还有加法和乘法关系都是一个接口Func的实现,而这个接口本身有toStr()和求导方法。递归构建好表达式树之后直接对根节点使用求导方法就可以得到结果。
2、度量分析
第三次作业我使用了工厂模式。所有的因子和关系都是一个接口Func的实现,程序在整体结构上清晰了很多,扩展性也提高了。但是由于递归的结构,使得结果的化简变得比较困难。我在每个因子和关系的求导方法中加入了一些判定,例如在加法关系求导方法中若左右两项都为常数则合并。但是由于各项的复杂性很难做到所有的同类项都被合并,这也是今后一个需要改进的地方。
第三次作业的优点在于使用了工厂模式使程序的结构更加清晰,可拓展度提升。同时使用了Str类来管理解析字符串的方法,在Main中只完成输入和输出的工作,整体更加的面向对象化。但是仍旧有一些缺点存在,例如优化的部分和求导部分的重合以及优化的功能实现不全,还有一些方法的多次调用增加了程序整体的复杂度。
二、BUG分析
第一次作业
(1)非法字符,没有判断输入表达式含有非法字符的情况。
(2)优化问题,结果中的负数为系数时前面多输出了一个+号。
第二次作业
(1)没有处理首项含有+-号且第一项是x/sin(x)/cos(x)的特殊情况。
(2)优化处理时,如果系数是+-1且x/sin(x)/cos(x)的指数都为0时,输出会为空,实际应该为+-1。
第三次作业
(1)在Add()和Multiply()方法中的化简判断中,使用了递归式作为判断条件,导致多次重复递归,公测超时。
三、互测策略
在第一次作业的互测中,我主要还是通过读组里每一个同学的代码自己手动构造测试样例进行hack,找到的BUG多是WRONG FORMAT类考虑不周全的错误。这种方法耗时较多,效率也比较低下。
在第二次作业的互测中,我使用了Bash脚本批量测试+读代码定点打击结合的方法,效率有所提升。
在第三次作业的互测中,输入的表达式已经可以非常复杂,所以我使用的是自动化生成的测试数据+自己构造的数据做测试。对于结果的正确性,由于同学们的表达式五花八门且非常长,用肉眼已经很难进行判断,于是我使用了python的sympy库对表达式相等进行判断。
四、Applying Creational Pattern
第一次作业面向过程思想还很严重,应该对预处理方法单独建类管理,而且基本没有可扩展性。
第二次作业是在第一次作业基础上写的,所以整体程序的层次也是很难看,如果能把每一种因子单独建类,第三次作业就能直接利用了。
第三次作业使用了工厂模式,程序层次性更好,可拓展性增强,但是优化部分不尽如人意,我认为如果进行重构的话要新建一个类对求导结果整个字符串进行项合并、因子合并和去括号操作。
五、总结与反思
在这三周的时间里算是初步接触OO这门课的模式。本身java这门语言有编程经验的话很容易上手,也有很多方便的库可以直接用,省去了不少麻烦。个人学到的比较重要的几点一是写完程序一定要做覆盖性测试,我就是经常周日一晚上肝过了公测周一周二就只做优化和简单的测试,导致在互测构造测试数据hack别人的同时也不小心发现了自己的BUG;二是在优化的时候一定要事先想清楚自己的优化的适用范围,以及面对一些特殊情况的判断,或者说在条件不允许时干脆不优化保证自己的正确性也是一种策略,半斤八两的优化还不如没有;三是多看下大佬们的代码,我在gitlab上看到了不少漂亮的大佬代码有很多值得我去学习。