OO第一单元总结

OO第一单元总结

2022.3.22 陈一文

Hw1

设计思路

uml类图:

image

  • 解析

    parser,lexer的思路 首先划分一下lexer和parser的职责:

    BNF表达式的最底端都是由一些基础符号元素, lexer的作用就是把基础单元给提取出来,给parser用 比如 , **, +,-,,(,),一串数字等符号

    parser就是更上一层,对应着推理式中符号组成的逻辑, 通过你当前的得到的基础元素进行推理,边推理边next往后走 推理式对变量因子的定义, x【**2】之类的,parser就可以写成peek到“x”,这个时候再peek一下 如果peek到的是**,那么接着往后走一个元素,得到2,直接就有了指数 如果peek到了别的,这是省略形式(或者WF),反正就是parser的时候要根据题干推理式来边往后看边做讨论,看的时候提取有用的信息, 题干的格式就基本对应了parser讨论的格式

  • 化简

    第一次作业中我将 Variable和constant合并了成了一个带有coef和exp(参数,指数)的Variable class,

    想法是:每个variable,expr可以获取其hashmap然后通过递归+hashmap模拟+,*运算,回传来得到总得hashmap,

    hashmap就是指,局部化简好,同类相合并好的 多项式的 指数和系数 构成hashmap

    这个hashmap是<指数,系数>然后比如expr*expr就是两个hashmap乘一下,模拟一下乘法, 同时根据乘法结果得到一个hashmap, 根据这个合并好同类项hashmap重新更新我的表达式树。

程序分析

  • 规模分析:

    共365行

    File totLine totMethod
    Variable.java 25 1
    Term.java 62 2
    Parser.java 108 3
    Main.java 92 1
    Lexer.java 51 4
    Factor.java 12 2
    Expr.java 123 3
  • 类的内聚和相互间的耦合情况、圈复杂度

    class OCavg OCmax WMC
    Parser 5.25 13.0 21.0
    Main 11.0 11.0 11.0
    Expr 2.3333333333333335 7.0 21.0
    Lexer 1.8333333333333333 5.0 11.0
    Term 2.0 4.0 10.0
    Factor 1.0 1.0 2.0
    Variable 1.0 1.0 2.0
    Average 2.689655172413793 6.0 11.142857142857142

可以看到主要耦合、复杂度在于lexer parser,因为递归下降需要边判断情况边解析,分支控制结构较多

bug分析

没有bug开心~

测试思路

随机测试,sympy+subprocess 以后的都差不多

综合评价

第一次作业,感觉完成的简单又漂亮,没有bug, 而且可以在一次化简直接得出结果,维护的hashmap结构,在打印时比树上打印简单很多,又不容易错,可以看到后面的bug大都来自于树上打印display()

缺点在于,适用性比较小,hashmap仅能维护标准的x多项式,拓展性不是很好

Hw2

设计思路

第二次作业情况更加复杂,

  • 加入sin,cos
  • 加入函数
  • 加入sum

我用表达式树来说明一下

(image

image

image

第二次作业的uml图和第三次作业的类似,因为基本没有大改,见第三次作业

程序分析

  • 规模分析:
    共1200+行
File totLine totMethod
Cos.java 142 11
Expr.java 256 19
Factor.java 56 6
Func.java 28 7
FuncItem.java 38 5
Lexer.java 63 4
Main.java 81 5
Num.java 54 4
Parser.java 332 8
Sin.java 161 11
Term.java 371 9
Variable.java 80 7
  • 类的内聚和相互间的耦合情况、圈复杂度
class OCavg OCmax WMC
Factor 1.0 1.0 7.0
Func 1.0 1.0 5.0
FuncItem 1.0 1.0 8.0
Num 1.4285714285714286 3.0 10.0
Variable 1.7272727272727273 6.0 19.0
Expr 1.9473684210526316 8.0 37.0
Lexer 2.3333333333333335 8.0 14.0
Cos 2.4166666666666665 7.0 29.0
Sin 2.4166666666666665 7.0 29.0
Term 3.5789473684210527 18.0 68.0
Main 4.0 7.0 8.0
Parser 4.066666666666666 10.0 61.0
Average 2.3983739837398375 6.416666666666667 21.071428571428573

老问题parser,lexer复杂度高; 随着问题变复杂, 维护expr, term这些关键节点的类变得更为复杂,同时bug也更加频繁

bug分析

  • bug1: display在考虑输出时, 将通过给出在处理子factor display “+0” 化简时试图去除“+”,但未考虑在常数情况下,由于term将常数整体作为term的属性coef, 此时没有factor会display出“”, 此时会出现RE错误。

  • bug2: sum(i, -1, 2, xxx) 为考虑到sum的上下限可能为负数, 导致在解析中出错

  • bug3: Hashset遍历中修改元素,以至于hashcode值改变,而hashset中元素对应位置没改变, 在合并时,比较hashset是否相等.equals()调用的实际是 .contain()这样一来,就无法在contain中以hashcode查找该值,导致无法合并一些同类项

发现对面的bug共3个:

  • \[sin(-1)**2 \]

    会有format错误

  • \[sin(-1) \]

    处理优化的问题

测试思路

同上,但更多采用了特殊案例构造的方法

综合评价

这次作业我不满意,虽然方法没有问题,但是花的时间太多,心态越写越差,没有时间去大规模测试,导致出现了一些bug, 由此见得时间管理、测试的重要性

Hw3

设计思路

uml类图(适当简化了一下依赖关系,要不然图片会比较乱)

image

程序分析

  • 规模分析:
    共1400+行
File totLine totMethod
Cos.java 177 11
Expr.java 296 18
Factor.java 56 7
Func.java 28 6
FuncItem.java 38 4
Lexer.java 63 4
Main.java 99 2
Num.java 54 6
Parser.java 371 11
Sin.java 196 11
Term.java 375 14
Variable.java 80 7
  • 类的内聚和相互间的耦合情况、圈复杂度
class OCavg OCmax WMC
Factor 1.0 1.0 7.0
Func 1.0 1.0 5.0
FuncItem 1.0 1.0 8.0
Num 1.4285714285714286 3.0 10.0
Variable 1.7272727272727273 6.0 19.0
Expr 2.0 8.0 42.0
Lexer 2.3333333333333335 8.0 14.0
Cos 2.9166666666666665 11.0 35.0
Sin 2.9166666666666665 11.0 35.0
Main 3.0 5.0 9.0
Term 3.6315789473684212 18.0 69.0
Parser 4.6 10.0 69.0
Average 2.5555555555555554 6.916666666666667 24.76923076923077

随着cos,sin允许内部嵌套,cos,sin的复杂度也高了起来。

分析复杂度和bug产生的关系

image

其中Cos Sin类中的display()方法,复杂度是最高的,也在最终产生了bug,应验“高复杂度产生高bug概率”惨痛教训

bug分析

  • bug1:

\[sin((-x)) \]

, 在化简时,没有把-x看作一个term,而是把它看作了factor,属于题目理解的不仔细,对于format没有认真考虑,而在后续写评测机时,没有检验格式的正确,导致了漏网的bug

发现对面的bug共11个:

  • 类似于bug1的sin((-x))

  • sum上下限含有负数,大于int,

  • sum代入常数后出现 2**3的情况

测试思路

​ 自己手动构造的情况多了起来,hack了不少真不戳!

综合评价

​ bug减少了不少,基本没有改什么代码, 做了不少测试, 但由于对新的内容理解不深考虑不周还是有1个bug

三次作业整体分析与体会

架构设计体验

  • 第一次作业采用了递归下降+表达式树的方式奠定了基础
  • 第二次作业在此基础上加入sin,cos,函数,sum, 加入了换树的方法,重写Hashcode Equals等方法,可惜时间不足bug有点多
  • 第三次作业在此基础上优化了一点,同时加强了测试debug
优化中的感想

关于优化, 第一次和第三次作业优化较好, 考虑了sin0, cos0, sin^2x + cos^2x 的情况,没有优化很多,优化和bug是共轭的, 主要还是注重架构和逻辑上的正确性为上吧,正确性为主,优化为辅~

测试:关于找bug与写bug的心得

​ 关于测试三次均采用了随机样例测试+边界数据自己构造, 第一次由于冯如杯没有怎么hack也没被hack, 第二次由于半重构,为了扩展性加入大量新的方法,导致课下测试debug时间不足bug比较多,被hack了1次, hack了别人3次, 第三次bug减少了不少,但由于对新的内容理解不深考虑不周还是有1个bug, hack了别人11次。

心得:多做测试!多看题目!多自己构造!

在听完何天然佬的研讨课发言以后,我又有新的心得:随机测试不能完全随机, 应带建立特殊数据池, 对一些边界情况进行更加自动化的测试。

真情实感

OO第一单元就要结束了,下周就要喜迎电梯了(悲。不说别的了,OO第一单元一下子就感受到了强度,第一单元满意之处还是很多的, 比如自己的架构表达式树可扩展性很好,也可以适用于更多的情况(虽然没出更多的情况hh),但总体上我不是很满意,bug有点多,测试有点少,导致自己辛勤劳作无法体现在得分上有点不开心,本来多好的做法哎。不过呢,总是要往好的一面看,至少自己学到了不少,也可以更好地在高压下进行学习码代码,也明白了面向对象的多态封装继承,以及可能会用到的设计模式,还学习了一把stream,lambda表达式,虽然用的极其不熟哈哈哈。更重要的是:我很感谢那些帮过我的同学,助教,超级感谢!他们都超级好! 与此同时,我也尽心尽力地帮助了不少好朋友,希望大家继续互相帮助不断前进吧~电梯月我来啦求轻虐。

image

posted @ 2022-03-22 18:03  cywuuuu  阅读(239)  评论(2编辑  收藏  举报