OO Unit 1 Summary

第一次作业

内容是幂函数求导。经过寒假的pre作业,对于java的基本语法和容器有了简单的了解(比如不会再使用静态数组了),因此完成作业难度也并不大,从设计到完成,大概花了一个下午+晚上的时间,中间包含了两次小重构(BigInteger、负指数),可见还是要好好读指导书。

由于没有Wrong Format的判定,因而没有想到正则表达式的方法,写了比较复杂的if-else(主要是针对省略系数和指数的情况)来解析输入。Poly类使用的Hashmap存储<指数,系数>键值对,扩展性较差。

程序结构

UML图

8dF1eJ.md.png

度量分析

8dFMyF.md.png

可以看出此时的设计非常面向过程,仅有两个类且基本没有依存关系,大部分工作都由主类完成,分为输入、解析、求导、输出四个部分,基本是C语言的套路,Poly类主要作为数据管理使用,本质上只是一个HashTable,尽管编写简单,但不具备很强的扩展性。

自动测评

室友按照讨论区的帖子编写了自动测评程序,主要是调用xeger根据正则表达式生成随机字符串、调用os.popen输入shell命令、调用sympy计算求导标准答案、代入x进行比对。实际效果不错,找到了一个罕见的bug(解析系数时对于省略系数的处理有一些小问题),最终经过了1000轮测试,提交公测。

公测

在中测、强测所有点AC的情况下,对于省略系数、省略指数、合并同类项、正项提前等均做了优化,因而取得了性能分满分。

互测

此时还没有开发自动对拍程序,只是手动构造了一些数据测试,其他人的代码也没有很仔细地阅读,只是看了个大概思路。最终一共6个数据并没有测出任何bug,整个room到最后0刀命中,应该是都通过了强测而没有bug。

第二次作业

引入了三角函数以及乘法,难度稍有增加,设计的时候我看了看去年的前三次作业的指导书,因此面临一个选择:继续第一次的架构,还是直接改用第三次的架构。两种选择分别将任务量分布在本周或者下周。最终主要考虑了优化输出的因素,觉得第一次的架构比较方便优化,因而沿用了老的方法。由于改进较少,只花了一下午+晚上的时间就完成了迭代。

程序结构

UML图

8dFJF1.md.png

度量分析

8dFKQU.md.png

延续了第一次的设计,并没有过多的模块化层次化思想。针对三角函数的迭代在于将HashMap的键更换为<sin,cos,pow>三种指数的三元组,值仍为系数,导函数可以利用 x^a^sin(x)^b^cos(x)^c^ 的求导结果来一次完成,比较简单。

由于引入了WF,因此设计了层次化的正则表达式来判断格式、解析输入,明显比第一次作业逻辑更清晰简洁。

自动测评

受到第一次作业的评测程序的启发,这次我在其基础上开发了对拍程序,可以同时判断多个程序的输出,用来给自己的程序找到了几个bug,效果更加显著。不过对拍程序的主要威力还是在互测中展现。

公测

限于时间因素没有进行彻底的优化(讨论区同学提到的递归下降等),只是优化了诸如 f(x)-f(x)sin(x)^2^、f(x)cos(x)^2^+f(x)sin(x)^2^的前两种情况。最终强测中全部AC,取得了95分,成绩尚可。

互测

自动对拍大显神通,测出了三个人的WF(关于最大指数)、一个人对于--+的解析、两个人的优化等多个bug,并经过组合构造出可以一刀4个人的恐怖数据。渐渐感受到了自动生成数据的威力。屋内几位同学竞争激烈,最终我们几人在内卷的氛围下(以及不切实际的无法合并修复的期待下)每个人都hack了20-30次,然而经过被hack人的合并修复只得到了3个bug的分数。可见指望同一个bug发家是不现实的。

第三次作业

引入了三角函数复合以及表达式因子,设计难度大幅提升,需要重构。不过我在上一次作业时已经简单思考了这次作业设计,加上老师在课程中的提示,最终编码阶段相对比较简单,只是花费了比较长的时间,24小时从头开始完成了1000行代码。

程序结构

UML图

8dFtW6.md.png

度量分析

8dFdyD.md.png

进行了彻底重构,对于加、乘运算以及三角函数、幂函数、常数分别设计一个类,继承自共同的Term类,分别实现求导、输出等方法。

输入部分参考了讨论区同学的层次化解析设计,依次将三角函数或表达式因子的括号内部分替换解析,然后利用小正则解析被替换部分,如此递归解析即可达成目的。中间利用LinkedList手写了括号匹配算法,利用了数据结构的知识。最终输入解析为表达式树的结构。

求导部分也是递归设计,实现求导规则即可,难度很小。

输出部分也是递归调用,在此过程中写了优化。我最初写了很复杂的合并同类项的优化,然而最终发现超时严重,只能放弃大部分优化而只优化了×0、×1、+0等最简单的操作。

自动测试

生成输入的程序稍复杂,我参考了github上的一些代码,依次写出生成项、因子的函数,每个函数调用不同类型的正则,如运算符、指数、三角函数等。其余对拍部分则没有修改,可以直接使用。然而此次自动测试出现了覆盖性不足的问题,在互测中体现了很多。

公测

在放弃大部分优化后,没有出现TLE或者WA,AC了全部测试点得到98分,应该说还是比较满意的结果。

互测

见到了自动测试的弊端。别人轻而易举的找出了我的bug(cos(0)被我化简为了0,一个bug惨遭7刀,一波合并修复带走),而我却找不到他们的bug(除我外一共有10次hack)。公布结果后查看数据,发现数据主要针对优化,明显是研读过代码而针对性地设计的数据,而自动化测试远远达不到这样的针对性,这加深了我对于测试方法的理解。覆盖性与针对性,需要自动测试+手动构造相结合,才能达到最好的效果。

对象创建模式重构

考虑工厂模式的创建方法,我对对象构造方式进行了改变。这里一个问题就是不同类的构造方法需要的参数个数不同,我选择的设计是传入一个元素类型为Object的ArrayList,从而实现变长变类型参数的传递。

另一种方法是始终传入一个字符串,然后在每个类的构造方法中解析字符串,这需要大规模改造现有类,因此我没有使用。不知道是否存在更好的解决方式,希望能看看其他同学的设计。

8dFwOe.md.png

反思

在前两次作业中的思路还比较偏向于以前的面向过程思路,第三次的重构中学会了很多思想。纵观整个单元,除了编程能力和设计思想的提升外,对于测试、优化、工具的运用能力也明显提升了。

感谢课程组的精心设计和答疑,以及讨论区里各位同学的积极讨论。希望在之后三个单元的作业中也能够顺利完成,提升编程水平和对面向对象思想的理解。

原文地址:https://www.cnblogs.com/zkwang/p/12514351.html