面向对象第一单元总结

面向对象第一单元总结

第一单元三次作业分别为简单多项式的求导、支持简单三角函数多项式的求导以及支持嵌套因子和表达式因子的求导。总的来说,三次作业应采用迭代式开发,作业依次向之前数据兼容。本文主要从架构分析和程序结构、bug的处理与测试和对比与学习体会来总结第一单元。

1.架构分析和程序结构

1.1 需求分析和设计

  • 第一次作业

    输入格式正确的多项式,按一定规则输出它的导函数。由于幂函数有严格的正则规范,所以很容易想到以正则表达式+捕获组结合的方式进行提取。而由于输入是保证格式正确的,可以预先将表达式中的空白字符删去来简化正则表达式。而对于重复的+-符号,也可以通过预处理进行简化。

  • 第二次作业

    输入包括简单幂函数和简单三角函数的多项式,并输出其导数。对于可能出现的格式错误,不能套用第一次作业的方法进行分析。可以在去掉空白字符后,将表达式从多项式分解为项,并且逐项分析。需要注意的是,项的第一个因子不同于项内其他因子,由于多了一个符号,在匹配的时候要特别注意。

  • 第三次作业

    输入包括简单幂函数和简单三角函数及其组合和嵌套的多项式,输出其导数。分析的难点在于括号内部嵌套结构和递归结构。对于空白符号所造成的格式错误,我采用了正难则反的方法,找到不合法的情况并进行正则匹配,一次解决。对于其他格式错误,交给判断因子的正则表达式。每当读取到sin(.+?)或者cos(.+?)或者(.+?)的时候需要递归判断内部情况。在此之前还要将括号进行处理,可以将它修改成其他字符以方便判断。

总的来说,针对这三次作业,可以将程序分为几个类,流程控制、输入输出控制、以及项类、因子类和表达式类。流程控制即Mainclass类,为程序入口。输入输出控制负责将输入通过正则表达式匹配的方法存入相应的数据类——项类、因子类和表达式类等。数据类负责存储信息。

1.2 架构分析和反思

  • 第一次作业&第二次作业

    由于前两次作业采用了相似的架构,所以将他们放在一起进行分析。在这两次作业中,我没有将因子单独列出来成为类,因为这两次中的单项式还比较简单,只需要一个单项式类就可以储存全部信息。

    (1)UML类图

(2)复杂度分析

(3)总结

第一次和第二次作业结构较为清晰,但是extract方法解耦合不够,导致复杂度过高。内部匹配各因子的方法应该再次拆分出来形成新的方法,减少方法的复杂度。

  • 第三次作业

    第三次作业经历了一次比较大的改动。因为增加了递归的方法,所以引起了较为严重的依赖,而且由于第二次作业中extract方法留下的“遗祸”,部分类代码长度过长,由于后期忙于debug和测试,也没有进行系统修改,这是很大的失误。

    (1)UML类图

(2)复杂度分析

(3)总结

关键的问题在于extract方法和ext方法的解耦不够。其次,我的求导方法也不甚令人满意。我并没有采用表达式树的方法,而是沿用了将表达式分解为项,再分析因子的模式。因此term类中会包含sinfac、cosfac、expression类,但是系数和x指数我并没有单独建立类。从这点看,面向对象的思想运用的还是不够。

2.Bug的处理与测试

2.1 Bug处理

  • 第一次作业&第二次作业

    前两次作业比较简单,在写完程序后,我通过一些基本的测试数据就基本完成了debug的工作。一般来说,在刚写完程序的时候,会先用基本数据验证,然后再推广到复杂数据。我的方法是将数据按不同的类别分类数据然后进行测试。比如系数是0,1,-1或者其他数字,符号是否有冗余等等。这样的数据会更具有全面性,能验证输出函数的正确性。

  • 第三次作业

    第三次作业的测试任务很重,而且增加了格式错误的测试任务。这次的测试数据帮我找到了很多程序中的错误。首先对于判断符号和数字中的空格,我采用了String icon = "([+-]\\s+\\d)|(\\d\\s+\\d)";+正则表达式的方法进行判断。但是这样会导致项之间的+-号和数字的正确组合被误判为wf。在仔细分析数字前面的空格和符号的所有情况后,我建立了一个有限状态机来判断。而且,明显的优点是可以一次性判断,不用递归判断。其次还有贪婪匹配和非贪婪匹配的问题,由于在第三次作业中,我使用了置换的方法匹配外层括号,并且用了通配符.来匹配内层内容,这就要求使用非贪婪匹配方法。通过()*()即表达式因子等的数据可以明显看出问题所在。

2.2 测试

  • 针对自己程序的测试
    我主要采用了手动生成测试数据的方法。针对第一次第二次的作业,这种方式还是可以满足需求的,因为第一二次作业的数据较为简单,可以通过自己的策略生成具有覆盖性的测试数据。第三次作业的测试稍显困难,我一部分通过测试的方式,一部分通过分析代码和功能基本做到了覆盖性测试。但是这也提示我在之后的课程中早日完善评测机的搭建。

  • 在互测中针对其他程序的测试

    我采取了与测试自己程序相似的策略。先使用基本数据,验证初步的正确性,再通过交叉类型的数据进行验证。我觉得很重要的一点是阅读代码并且分析。以第三次作业为例,我发现有很多同学sin(- 3)型的数据都会正常计算。这就是由于判断空白字符的方法出现了问题。还有在进行深层嵌套比如((((((((((x))))))))))的时候,部分程序会出现tle等问题。

3.对比和学习体会

  • 自我反思

    第三次作业并没有进行优化,导致部分输出过长,有冗余的部分。而且由于代码复用部分过长,代码风格出现了问题。在面向对象这点上,代码中运用了面向对象的思想,但是还不完全,工厂模式和接口的使用还需要进一步学习。虽然在强测和互测中没有出现问题,但是我的代码还有很大的提升空间。

  • 阅读优秀代码后有感

    解耦合和减少依赖,使每个代码段或者类完成有限的功能是面向对象编程中必要的部分,也是面向对象的精髓之一。这几份优秀代码的共同特点就是面向对象思想运用得很好,做到了分而治之。其中化简部分的算法也值得我学习。

posted @ 2020-03-20 11:41  歌未竟  阅读(172)  评论(0编辑  收藏  举报