BUAA_OO_2021_第一单元总结

BUAA_OO_2021_第一单元总结

OO第一单元以表达式求导为主题,让我们学习了面向对象的思想,用面向对象的程序来处理问题。经过了三次作业,我学会了用各种来处理各种数据,通过对程序的不断重构,我深刻地体会到了面向对象程序更强的鲁棒性和更清晰的层次架构,也在一次次痛苦的思考中提升了自己的代码能力。

基于度量的程序结构分析

OO度量的一些指标:

ev(G)基本复杂度,是用来衡量程序非结构化程度的,非结构成分降低了程序的质量,增加了代码的维护难度,使程序难于理解。因此,基本复杂度高意味着非结构化程度高,难以模块化和维护。实际上,消除了一个错误有时会引起其他的错误。

Iv(G)模块设计复杂度,是用来衡量模块判定结构,即模块和其他模块的调用关系。软件模块设计复杂度高意味模块耦合度高,这将导致模块难于隔离、维护和复用。模块设计复杂度是从模块流程图中移去那些不包含调用子模块的判定和循环结构后得出的圈复杂度,因此模块设计复杂度不能大于圈复杂度,通常是远小于圈复杂度。

v(G)圈复杂度,是用来衡量一个模块判定结构的复杂程度,数量上表现为独立路径的条数,即合理的预防错误所需测试的最少路径条数,圈复杂度大说明程序代码可能质量低且难于测试和维护,经验表明,程序的可能错误和高的圈复杂度有着很大关系。

对于代码的分析主要以LOC(Lines of Code)为主,它可以代表方法的规模以及类的总规模,也一定程度上体现了代码的复杂度。

第一次作业

  • UML类图如下:

  • 复杂度分析:

  • 代码分析:

第一次作业由于比较直白,故采用了一种近似于面向过程的方法解决,其中Main类为主方法,Factor类为因子类,Parse类为表达式处理类,Deri类为求导类,各自做各自的事情,本质上说是面向过程,不过是把不同的函数封装在了同一个类中。

第二次作业

  • UML类图如下:

  • 复杂度分析:

  • 代码分析:

第二次作业增加了三角函数和嵌套,经过思考发现,每一项可以变成a*x**b*sin(x)**c*cos(x)**d的形式,于是还是用了面向过程的方法解决问题,使用了Brack类来进行拆括号操作,提取每一项并把每一项化成上述形式,直接求导后化简,其他类基本是在第一次作业的基础上进行了一定的迭代,用非常符合我们手算的思路解决了这一次作业。
当然,这种暴力的方式也因为很难考虑周全而带来了代价。

第三次作业

第三次作业的主要架构如下:

  • 具体的UML类图如下:

  • 复杂度分析:

  • 代码分析:

第三次作业增加了三角函数内的嵌套以及WF,经过了一整夜的思考,把之前的作业全部推翻,从零重构。这也是我觉得第一单元自己最应该反思的一点,只想着暴力完成简单的任务,没有想后面迭代开发更复杂的任务。既然是面向对象课程,不用面向对象思维解决终归是不行的。
这也算是第一次真的用面向对象的思想完成作业。在学习了工厂模式以及互测中其他同学的代码后,我把常数因子、三角因子、幂函数因子都继承了因子类,每个因子都有匹配串、得到指数和求导三个方法,递归得到求导结果。
整个作业采用了递归下降的思路,把整化零,从表达式到项,从项到因子,各个因子嵌套求导,最后递归返回结果,其中Cos,Sin,const等因子继承了Factor类,实现了其中建立串、得到系数指数、匹配串以及求导的方法,Wrong类对空白字符和一些明显的错误进行了处理,Printout类对输出进行了极其有限的化简。

小结

通过对代码的度量,不难发现自己的代码非常不优雅,很多方法的复杂度都是超标的,这说明了我设计的代码耦合度很高,没有很好的扩展性,而且这些方法也往往会成为程序的漏洞,因此在以后的程序设计中应该尽可能地把方法拆分简化,让类和类之间的独立性更高,让自己的程序更有鲁棒性。
同时对比自己第一次、第二次面向过程的程序和第三次面向对象的程序,前者的代码复杂度以及行数相当高,超标的方法非常多,后者虽然有着更复杂的架构和内容,但复杂度却不是很高,这也足以看出面向对象程序的优越性。

BUG分析

第一次作业

第一次作业在强测、中测以及互测中都没有出现bug。
在互测阶段找到了两种bug,一种是连续三个符号比如++-x这种,一种是形如x**4*x**-4这种在化简中出现了形式错误。

第二次作业

第二次作业强测出现了一个bug,一个bug带走了4个测试点。问题出现Parse类中的parseString方法,拆括号的时候没有考虑负号开头内部项要变号的需求。可以看到对应方法的行数以及圈复杂度很高,用血的教训证明了暴力一定会付出代价
在hack别人的时候也出现了一些bug,比如多层嵌套括号时会TLE,多层括号附带多个符号时由于没化简而导致输出出现WF,由于一二两次作业的跨度比较大,所以在第二次作业中的hack情况非常惨烈。

第三次作业

第三次作业出现了两个bug,都是WF导致的,这一部分的代码并没有复杂度或者行数的问题,仅仅是因为自己对javaString类以及对于WF情况考虑不周导致。千万别轻易想着化简,化简总会带来意想不到的后果。一个问题出现了我在一个项内有0因子时直接跳过了判定,导致后边的WF没有判断,一个是(((())))这种情况,Java里的空串使用时会报错,在C语言中一个字符串=""是无可厚非的,但在Java中就会报NullpointerException,这在以后的作业中都是值得谨记的一点。同时,出现bug的方法也是普遍体现出行数多、各种复杂度都很高的特点。
由于不允许HackWF,所以这一次屋里比较平静。我只找到了一个bug,就是有些同学把cos(0)化简成了0,再一次说明了第三次作业的化简一定要慎之又慎。

发现bug的策略

在第一次和第二次作业中,采用了白盒测试的方法,通读了所有的代码,针对代码里出现的漏洞以及自己作业过程中出现的问题进行定向debug,有效性比较好,在阅读别人的代码时往往针对对输入和输出的处理部分发现其中没有考虑周全的部分。
第三次作业由于太过复杂,阅读所有同学的代码不现实,也很难读懂,因此根据指导书自己思考了几个可能会错的点,效果一般,在屋里有一个同学发现了6个bug,而我只突破了其中的一个化简错误。

自动化测试

在上学期计组课程中自动化测试起到了很好的作用,这几次作业因为答案的多样性,没有构造自动化测评机和自动生成样例的程序,仅仅把几份代码通过一个批处理文件快速得到结果。

重构

从第一次作业到第二次作业几乎都是在面向过程的基础上进行迭代开发,经过了第三次作业的全部重构后,整个代码的性能、框架、复杂度都得到了很大的改善,真是重构一时爽,一直重构一直爽

心得体会

我觉得OO最痛苦的过程就是从刚发布作业到思考成型的过程,由于面向对象的思想不是很成熟,设计建构显得非常困难,但也算是勉勉强强完成了任务。通过第一单元的学习,有以下几点反思和心得。

  • pre要认真做
    因为寒假最后一周自己在旅游,而开学之后立刻就进入了HW1,因此pre阶段算是完全咕咕掉了,自己也因此付出了代价。没有了解工厂模式、接口、继承这些概念,导致我没有用面向对象的架构起步,在第二次作业中出现了bug,以及在第三次作业中痛苦的完全重写。

  • 讨论区
    讨论区里大佬的帖子往往有奇效,从代码架构、bug分析、程序优化、自动测评以及设计思路上都给了我很大的启发。认真读完每一条帖子会让自己的工作事半功倍。

  • Java语言学习
    每一次作业中都有提到不要重复造轮子,遇到一些棘手的问题时多去搜索一下前人是否已经有了解决方法往往比自己暴力解决要好得多,Java语言中的设计模式、自带方法、多态继承、各种容器、正则表达式等都是我们解决问题的利器。

  • 迭代开发
    作业要求既然是迭代开发,在最开始就要为代码建立良好的可扩展性。可以通过往年的博客大概了解到后面作业的要求,在设计过程中要综合后面homework的需求进行开发。

posted @ 2021-03-27 12:48  SilenceBQ  阅读(105)  评论(2编辑  收藏  举报