OO第一单元总结
前言
第一单元 OO 作业的主题是求导,从最简单的幂函数求导,到添加三角函数求导,再到最后添加嵌套规则。(对熬夜有了新体验,OO 作业比较适合晚上写,OO 博客也是一样 doge)
一、代码分析
分析将主要通过UML图,OCavg 和 WMC 三个方面来分析。
OCavg 代表类的方法的平均循环复杂度
WMC 代表类的方法的总循环复杂度
第一次作业
第一次作业总的来说很简单,只需要对幂函数进行求导,而且没有 WF 的判断需求,我直接上大正则匹配,同时尝试了一下面向对象的编程模式(虽然最后还是面向过程的更多一些)。
UML 类图
复杂度分析
总结
虽然想着的是面向对象,结果还是面向过程,这一点在 MainClass 充分体现了,所有的表达式拆分,求导完的组合都是在这个类中实现的,十分笨重。
不过在这次作业中,因子作为基本单位进行求导,再将求导结果通过特定规则合并奠定了我接下来几次实验的总体的设计方向;对输入内容,从表达式拆解到项,再从项拆解到因子,最后求导完再从因子一层层往上进行合并最后输出。
第二次作业
添加了三角函数,为了扩展性,我从比较多的地方留了空间,方便新内容的添加,不过对于接口实现这个方面在当时还不是很了解;仍然是通过正则表达式来分类,从表达式拆解为项,项拆解为因子的方法来存储每一个因子,再通过合并的方式传递求导结果。
UML 类图
复杂度分析
总结
这个单元作业写得挺丢人的,自己没有理解好接口和类的区别,有的部分的实现,很明显太累赘了,比如 Factor 这个类还自己实现了一个接口 Function,然后这个接口和 Factor 这个类基本内容都是一致的,因为没有理解到接口可以直接管理实现了相同接口的类(找个地洞钻进去)。
在复杂度方面,Item 这个类需要兼顾 WF 的判断,拆解项为因子和因子的制造等多方面的内容,整个类很笨重,在扩展方面留下了隐患;同时我没有采用工厂模式,这个在扩展性方面比较差,在第三次作业针对这个方面进行了修改。
这次也是同样采用逐级拆分表达式为项,再拆分项为因子的办法,同时也考虑了对于第三次作业的扩展性,在表达式和项这两个类中都采用字符串加容器的管理方式,兼顾了合并同类项优化和扩展两个方面。
然后为了优化,专门建了一个优化的类,类似于打补丁的方式,对三角函数的化简进行了合并,然后不需要的时候删除掉就好了(嘿嘿)。
第三次作业
增加了嵌套因子,基本依托第二次作业开展的,然后从中分离出了一些方法,如 WF 的检查,因子对象的制造等,为了降低复杂度。
UML 类图
复杂度分析
总结
分解的层次可以这样理解:
-
Expression
- Item
- Factor
- Item
Factor 是一个接口,所有的因子都实现了这个接口,然后可以通过这个接口来调用所有的因子,就是一种多态的实现方法。
Expression 和 Item 类中都采用容器的管理方式,管理的对象主要分为两类,一类是求导前的集合,一类是求导后的集合,方便优化等多方面的管理。
这次作业相较于上次作业其实是一个扩展的过程,这个从 UML 图中也可看出来,添加了 Expr 表达式因子这个类,然后将 WF 的判断和因子的生成给分离出去,建造了 WrongFormatCheck 这个类和 Factory 这个工厂,将原本 Item 类中的东西分离出去;同时删除了上次的“优化补丁”,将优化融入到了整体中。所以整体的框架没有变化太多,第三次作业整体做起来还是挺快的,兼顾了优化和扩展性,比较多的时间花在了 debug 上(捂脸)。
分析下这次作业的内容,这次作业添加了嵌套因子和三角函数可嵌套这两个很伤的内容,主要是对正则表达式用户很不友好,所以为了能够使用正则表达式,我采用了先检查 WF,再通过预处理简化正则判断过程的方式来继续使用正则,出现 WF 的时候通过抛异常来终止程序。
其次工厂真是个好东西,如果还需要扩展的话,以后只要多个实现接口的类,添加个工厂制造方法,就可以比较容易就实现了。
这次的复杂度相较上次有一点点下降,整体的脉络也更加清晰了,但是类中的复杂度还是挺高的,主要是优化这个点,为了脱括号,拆因子,添加了挺多的内容。如果日后还需要扩展的话,或许将优化分离出来会有更强的扩展性。
二、Bug 与性能分析
Bug
自测:
在自测的时候发现了挺多 bug 的,主要是通过自己的测评机来发现的,主要问题一般为以下两个方面:
- 优化过度,该有的没了,比如第三次作业中的表达式因子的括号该不该脱;
- 对于对象的管理,一个对象有了多个管理者,这些管理者在调用和修改对象上出现了交叉,导致在一个管理者中对象被修改,在另一个管理者中其实不期望它被修改,修正办法就是不进行对象的直接管理权的赋值,而是通过先克隆,将克隆对象交予其他管理者。
- 数据生成主要是用 python 自带的正则包,最后一次的生成主要通过概率递减的方式来生成嵌套因子,基本做到了数据的全面性,在测试中非 WF 数据的测试没有出错;同时通过一定算法检查了自己的优化效果,在优化方面也给了自己很大帮助。
公测与互测:
本人在三次中测和互测中都没有出现 bug,前两次强测也没有出现 bug,但在最后一次强测中出现了关于 WF 判断不完全的 bug。本人在正答数据方面都做了很充分的测试,没想到最后竟然在 WF 方面的疏忽给了这次作业一个不完美的结局。
以下直接贴我的 bug 修复文档,说明得很详细,也给自己提个醒。
性能
在第一次和第三次的强测中,我的性能分几乎是满分(除了第三次 WF 的点的性能分没拿到);然后第二次强测中,大佬们太花了,真的玩不过,性能分算是看得过去。
优化主要是从细节出发,从最基本的因子的优化,将优化完的因子交给项;项再优化,把优化完的项交给表达式;表达式进行一个循环的优化,因为是单线的优化,就是固定优化几个方面的内容,比如三角合并,比如括号脱掉,直到没有再能合并或者能够脱括号的,不用考虑 TLE 等问题(课下通过 java 内置函数对上百近千的数据进行过测试,也没有超过规定范围时间,所以比较放心)。
其实只要做好了整体框架和层次的建立,优化可以说是水到渠成的事情,从局部最优到整体最优,是一种贪心的思想。
三、互测
本人在互测中没有出现 bug,然后 hack 了挺多人的,每次 hack 数据点在两位数,只要是互测屋中有 bug 的都 hack 成功了。
主要采用的方式就是,放进评测机,找到小于提交长度的关键数据上交,发现了大家的挺多问题的,从优化,到 WF 的判断,再到 TLE,主要找到的 bug 都是来自这三个方面。
比较遗憾的一点是对于很大一部分同屋的同学,自己其实没有很认真读他们的代码,一方面是自己比较懒,另一方面是看了整体的 java 文件,觉得没有很好地分类的和有层次性的代码都过滤了。不过也有幸和几个大佬同屋过,阅读完他们的优化方案和层次觉得受益匪浅。
四、应用对象创建模式
这方面的收获主要来自于工厂模式(真香)。
第二次作业一结束,就开始研究了关于工厂模式部分的内容,在第三次作业中将工厂模式充分应用,其实工厂类应该还要继续划分为具体的工厂,但是没有下一次作业了,就图方便全写在一起了。
对于工厂模式的体会,就是无敌的扩展性,因为每当需要一个新的内容,只需要将工厂类下新建一个分支,不需要对原有代码有过多的修改,就能够很好地实现一个新功能。
五、心得体会
- 测评机是个好东西,自己的测评机一开始设计就是扩展性和多应用场景的(曾经还一度想着商业化),在互测这方面节省了自己很多时间,十分感谢讨论区大佬们的建议,特别感谢qsy同学的“测评机”实现方法的介绍,不知道接下来的作业中还能不能用到测评机这样的好东西
上张图纪念一下(一家人就该整整齐齐)
- 拿到作业的第一时间绝对不是直接开干,应该先倒杯水,打开 typora 开始“抄指导书”,先对指导书中的内容充分理解,其实指导书本身也在框架和优化上有很多可以暗示,我们应该对作业有个整体的认识,然后才是着手代码,先搭好框架,再完善细节,这是我三次作业的体验(然后每周二晚上我都一直在喝水)
- 扩展性的保留将决定你接下来两三周好不好过,其实很感谢自己在第二周的时候考虑了挺多方面的内容的,第二周可以算是最难的一周,重构了两次,为了之后好添加新内容
- 讨论区是个好东西,互联网是个好东西,自己很多细节上的处理,特别提名
x**2 -> x*x
,都是来自讨论区同学们的经验,来自互联网上前辈们的 OO 总结,十分感谢 - 多和他人交流和分享,我觉得这是一个互助的过程,在向别人讲解自己的框架的时候,自己的认知也就更加具体了,然后对于模糊的地方也更加确定了;然后别人的分享对你也是一种启发,第二次作业的两次重构就来自与某同学的交流,然后我二次重构的周四写了一天
- 最后在接口,多态,模式,容器,字符串处理方面都有更加整体,立体的认识(挺好建议加大力度 doge,要是下次太难当我没说)
感谢助教和老师们在 OO 课程中的付出,辛苦啦!