OO第一单元总结

第一次作业

本次作业是简单的多项式求导,无非法输入。

仅有Main和Term两个类,Term中有系数和指数属性,设置了构造方法(包括字符串构造)、求导方法、输出ToString方法。了解到其实许多同学是利用Hashtable化简的,不过我的代码是Term继承Comparable接口排序后比较化简。

UML类图

Calculate Metrics

圈复杂度相对高的地方是ToString(字符串构造Term、求导次之),但考虑到要以较短的长度输出Term,ToString中的确需要一定数量if讨论不同情况。由于程序结构并不复杂,耦合度不是很高,基本符合“高内聚低耦合”。

强测

未发生错误,通过合并同类项、正项先输出以省符号性能分可拿满。

互测

Hacked

当常数项前有两个符号时,我的程序会把它们一起丢进new BigInteger()里导致Illegal embedded sign character

该bug贡献了本房间所有的活跃度。

Hack

无,不过合理怀疑本房间除我外并无bug。

第二次作业

本次作业中添加了sin(x)/cos(x),可能有非法输入。

三角函数的加入带来了新的机遇与挑战,可以观察到这次开始许多同学重构得到了可扩展性较好的代码,但是我没有。我仍使用了和上次相似度非常高的代码结构,将Term改为四元组。

UML类图

代码中出现出现了分工不明确的问题,如Combine(Term,Term)等出现在Main里其实有些奇怪。

Calculate Metrics

复杂度较高的地方类似于第一次作业。由于程序结构并不复杂,耦合度不是很高,基本符合“高内聚低耦合”。

强测

未发生错误。

未深入进行以\(sin(x)^2+cos(x)^2=1\)为原理的搜索,仅进行了显式的化简,所以丢掉了一些性能分。

互测

Hacked

未发生错误。

Hack

仅1次,某同学对需求的理解不正确,幂指数恰为10000时判了WF.

互测结束后发现room内另有一个bug我未发现,是三角函数指数非常大时的错误输出。生成数据时偷懒没有覆盖到这种情况,以后或许应该用第三次作业hack中提到的第二种shell测一些手造的数据。

第三次作业

本次作业加入了表达式因子,开启了嵌套的可能。!之前代码的可扩展性太差了,于是进行了彻底的重构。

与之前两次速成不同,这次作业是用周五下午写的,因为周二看完指导书后一直非常迷茫。不过相应地,进行了更多的思考终于对面向对象有了相对多的体会。

代码中解析输入表达式和得到求导结果均使用表达式树的形式,对于因子Sin\Cos\Pow\Num和运算符Add\Multiply均建立了类并实现了求导方法(实现了TreeNode接口)。

解析输入表达式对我来说是本次作业中的难点。直觉告诉我们这个是要递归去做的,但具体怎么递归仍有思路清晰与否之分、复杂度与实现技巧的优劣之别。我在判断表达式不含[]后进行了外层括号的[]替换,然后再递归的解决里面的东西是否是表达式因子/因子、是否合法等,WRONG FORMAT也是在构造过程中判断的。兴趣使然在周六进行了因子相乘、项相加的简单合并,最终达到的输出效果还是较为清晰的。

UML类图

Calculate Metrics

意料之中,本次复杂度较高的类是Expression和ExpTree。Expression用来解析输入字符串,以正则的group()先对项分组再对因子分组,最终构造得到ExpTree形式的结果。而ExpTree中包含了对子树求导的方法与诸如树和树相加/相乘并化简的方法。

LCOM(Lack of Cohesion in Methods):内聚缺乏性

CBO(Coupling Between Object Classes):对象类间的耦合

本次作业的内聚缺乏性仍保持了较低的水准,即“高内聚”,但耦合度大幅上升,一定程度是由程序结构变复杂导致的,但也有设计上的失误。

强测

本次强测迎来了大翻车,问题出现且仅出现在表达式中含有cos(x**2)/sin(x**2)的情况下。由于我在优化阶段将幂函数指数为2的输出改为x*x,却忽略了x**2为因子而x*x不为因子带来的输出不合法问题。

但是没有想到强测中含有cos(x**2)/sin(x**2)的点相当之多,据说是为求导后无指数设置的数据生成偏好,好狠啊。这次是想要追求下性能的,不过大概那些体现性能的点我WA了。555

互测

Hacked

被hack共12次,和强测同原因,已一次性修复。

Hack

【边民始知有生之乐】:由于强测的翻车,本次终于拥有了可加描述的hack经历。截至\(2020/3/21~11:47^{UTC+8}\)(bug修复阶段尚未结束),仍可通过hack得分13.9833。据观察,本room的bug较丰富,错误原因多种多样,有输出不合法、正确表达式误判WF、栈溢出、超时、求导错误等。

本次hack中使用了两个简易shell(其实是配合一些python代码食用的),一个大量随机生成数据测评指定代码并反馈错误点,另一个输入一组数据对房内所有代码进行测评并反馈错误输出及通过率。也就是说可以在找到错误点后先进行保留错误的简化,再通过拼接错误达到1v6/1v7的效果

但是由于某些roommates的bug易触发/没有太多时间分析伪·测评机找到的1v6数据是否同质,我应该提交过一些同质bug数据点。可能下周该把头像改成“Saber我错了”。

对象创建模式及心得体会若干

前两次作业的实现形式都颇有面向过程的遗风,直到第三次才对面向对象真正有所体会。作业12中我采用了构造函数模式创建对象(因为写起来实在是太简单了),而作业3中的Expression类其实有一点Factory的意味——以字符串为函数参数创建不同TreeNode类型的ExpTree,但不完全——实际上分工并不非常明确。将不同的运算和因子实现同一个接口以作为表达式树节点让人觉得很妙,可以体会到多态这一OOP特征。

另外CheckStyle其实给人很不一样的体验,过去写代码完全不注重代码风格(如果非说有代码风格仅仅是强迫症的体现,只是在方便自我阅读\debug\写得快),但面向对象带来的风格影响是他人的易读性、可维护性的注重,这在真正的工程实践中意义重大。不过一个在意的点是我们课程采用的CheckStyle单行代码最多不超过80字,有时候80字并不足以表述一个完整的意群。如在Expression类中我定义了一些字符串存储意义不同的正则表达式,但常常单行字数超限,最终只好通过压缩变量名来解决,实际上又降低了可读性。

此前的coding过程都是以实现一个(较小的)目标为导向的,很多时候注重写法甚至都是为了以更简洁的思维更快更高性能地完成。但自从有了OOP,感觉可以在意的东西还有很多、“设计”二字很重要,又从另一个角度体会了“程序设计艺术”一词存在的缘由。希望接下来可以学到更多。

posted @ 2020-03-21 13:00  Zars19  阅读(272)  评论(0编辑  收藏  举报