OO第一单元_多项式求导总结

第一次作业

UML类图


其架构不算复杂故引用了idea生成的UML


复杂度分析


  • 结构分析

    从UML图就可以看得出来,我完成的第一次作业依然主要是一个比较明显的“过程式编程”,可扩展性不强,基本上是使用一些较为巧妙的方法来处理输入使其规范化,利用幂函数结构的特点直接进行求导操作。
    从复杂度分析来看,复杂度最主要淤积在getDiffgetSymbol中,getDiff是对一个单独的幂函数进行求导,也是第一次作业的主体部分,而getSymbol则是对符号的处理和化简。
    对于化简,我直接将化简方法融合到求导方法中,使用容器HashMap来进行化简。

  • 自测和互测

    对于自测,我采用了手动构造特殊用例结合自动测试的方法。
    事实上,由于设计比较合理,所以这次程序整个流程比较完整且无特殊情况,所以在互测和强测中我都没有出现错误。
    而在互测中我使用我之前手动构造的用例对其他同学进行测试,也确实比较有效果。大家的bug主要集中在特殊情况结果为零时无输出以及化简导致无输出。从性能来讲大家都相差不多,而基本功能也都比较完善没有出现很严重的bug

  • 感受
    第一次作业整体比较简单,无论如何设计基本都能完成任务,但是由于我的可扩展性较低(可以修改后完成第二次的要求),所以也为我后续的“痛苦”埋下伏笔。

第二次作业

UML类图


其架构不算复杂故引用了idea生成的UML


复杂度分析(基础函数以power举例)


  • 结构分析

    这次我本来是基于上次进行修改后完成作业,但是在研讨课上几位同学给了我很大启发,所以我进行了完全的重构。
    我的代码分为三个大的分支:

    • Part1是基础函数以及求导,主要包括sin,cos,power以及他们的父类抽象类Function,这是整个架构的基础,其中包含了单个函数的信息以及基础求导方法。
    • Part2是字符串处理,主要是用来将输入的字符串进行格式判断,并且将正确形式的式子化简成xsincos三种类型连乘的形式,储存在Item中。
    • Part3是多项式求导,主要是用来对之前处理好的Item进行求导操作,然后将正确结果输出。

    本次作业重构后将求导权限下移到了单独的基础函数中,所以复杂度较为平均,而最大的消耗在于对字符串的处理,整体结构比较均衡。
    对于化简,我直接将化简方法融合到求导方法中,使用容器HashSet来进行化简,选择直接在项中加入toString以及hashCode等方法,对已经整理好的多项式进行化简。

  • 自测和互测

    对于自测,我采用了手动构造用例测试的方法,因为重构导致时间比较紧张。
    由于没有想到自己会在常数项中出现问题(最主要是自己测试不充分),导致本次作业出现了一个严重的bug,就是如果遇到number1*number2在整个字符串最开头时,由于字符串正则的漏洞,其会认为number1是一个单独的常数因子,导致其被忽略。这个bug出现后我又仔细的了解了一遍正则处理的规则。

  • 感受
    第二次作业经历了重构,也终于开始体验到OO的恐怖之处了,只有设计合理,扩展性强,就能轻松加ac。重构思想我放在最后讲述。

第三次作业

UML类图


其架构不算复杂故引用了idea生成的UML


复杂度分析


  • 结构分析

    这次我依然沿袭了上次代码,但是中途出现了一些小意外。
    我的最终代码依然分为三个大的分支:

    • Part1是基础函数以及求导,主要包括sin,cos,power以及他们的父类Function,这依然是整个架构的基础,其中包含了单个函数的信息以及基础求导方法,有所不同的是我将Function修改为正常类,让它可以实例化,以便我在后续过程中可以在循环时不必判断函数类型直接调用其方法。
    • Part2是字符串处理,主要是用来将输入的字符串进行格式判断,并且将正确形式的式子解析为Fx类的形式直接储存下来,这样就可以在后续求导中直接使用了。字符串处理我选用正则来匹配最内层的括号,并将其替换,另外在大神的点拨下,我将每次嵌套的数组下标存入替换单元中,这样便于递归。
    • Part3是函数求导,主要是用来对之前处理好的Fx进行求导操作,然后将正确结果输出。

    本次作业我把格式错误型判断单独解析,所以导致在复杂度分析上明显上升,事实上这也是一个不得已的办法,在初步构造时我没有保留重复括号等,只保存了我需要的一部分,导致后续无法合理的插入异常判断,故而我重新构造了异常判断,并将其放到了主类的方法中。优点在于我是通过正则和枚举的方法来判断异常;缺点在于代码较为臃肿,且需要我手动构造。
    本次作业求导权限依然在单独的基础函数中,所以复杂度较为平均,但由于设计略有缺陷,导致最大的消耗不仅是对字符串的处理,还有复合求导、格式判断的的部分。导致代码整体复杂度上升。

  • 自测和互测

    对于自测,我仍旧采用了手动构造用例测试的方法,因为特殊原因导致时间比较紧张。
    本次代码由于我的疏忽导致了一个非常致命的问题(一次合并修复了近20个点),就是我把一个关键的while写成了if,这导致我递归时在一些情况下会保留我替换的。记忆犹新的痛苦。
    在互测中,尽管我也被hack成了麻瓜,但是确实也没少成功hack别人;这次我从他人程序角度出发,主要观测了它们三个特点:

    是否误判WF:很多同学会把一些不是WF的数据误判。
    是否出现替换问题:这是从我自己代码中发现的问题。
    是否化简及递归会出现问题:因为有时间限制,这样我们就可以从此处入手。

论重构

作为一个面向过程选手,我可是没少经历重构,在重构的过程中,我发现一个最重要的问题:究竟是将权限上移还是将权限下移。其实,真正在我理解面向对象后,我才明白这个问题的解决办法:给每个类配适他自己的权限,而不是将权限和在一起。在第二次作业其实我留好了接口,但是直到第三次重构结束我才明白,我的借口不是不能用,而是权限配适不对,我把本该配适在表达式的功能通过特殊处理下放到项中了,导致我一开始我只能重构。最终我将求导权限分别放在不同层次中,最终成功重构。相信在本单元的学习结束后,我以后的迭代式作业不会再这么艰难了。

OO初体验

当然了艰难的过程换来的成功我确实十分享受,也发现了自己不少坏习惯并加以改正。但我特别感谢我的同学助教和老师,他们给了我很大的帮助,从研讨课上老师对我代码的指正和分析,还是助教为了公平重新构造强测点,抑或是同学分享自己的优秀思路。相信我能在OO之路上坚持走到最后,因为有大家的陪伴,我们每个人都不会感到孤独和无助,笔芯。

原文地址:https://www.cnblogs.com/GantenOOHW1/p/12534871.html