OO第一单元总结

OO第一单元总结

总体设计思想

处理流程

首先,为尽量保证正确性,我选择了先完全展开后化简的操作。方法处理总体分为三块。

  • 输入与预处理:MainClass.java及官方包、FuncManage.java

  • 表达式解析:Parser.java

  • 表达式化简:Simple.java、SimpleTerm.java、Termfact.java

流程如下:

 

解析方法:

自定义函数->HashMap<Name,Expression>

表达式->表达式树

 

 

迭代开发与拓展

  • HW_1:

    • 目的:去掉含有+,-,*,**的表达式中的括号。

    • 解决方案:构建Add、Sub、Mul、Bracket类。

    • Parser解析按照运算优先级依次处理Add/Sub、Mul、Pow(转换成连乘)、Bracket(Sin/Cos)、Num/Alpha处理。

    • Sub表达式前为负号,转换为Bracket类,拆分成项后变号。

    • Mul表达式转换为Bracket类,拆分成项,依次相乘。

  • HW_2:

    • 目的:在第一次作业基础上增加sin(),cos(),sum()函数,自定义函数。

    • 解决方案:补充sin()、cos(),sum()类。

    • 自定义函数及Sum函数预先处理,将函数名和表达式存入HashMap中,预先进行表达式自定义函数及Sum函数处理,以实际参数进行字符串替换掉形式参数再放到表达式中进行解析。

  • HW_3:

    • 目的:在第二次作业的基础上增加了嵌套函数处理问题

    • 解决方案:Parser类中增加自定义函数解析方法,采用递归处理方法处理嵌套函数。

    • Parser解析按照运算优先级依次处理Add/Sub、Mul、Pow(转换成连乘)、Bracket(Sin/Cos/Sum/Func)、Num/Alpha处理。

化简:

  • 合并同类项:将各项完全展开后以指定顺序排列,以HashMap存储<系数,表达式(连乘式)>,如果遇到去掉系数的项后表达式相同则合并。

  • sin(0)=0,cos(0)=1

  • sin(-项)=sin(项),cos(-项)=cos(项)

  • 在研讨课上,同学还分享了sin(表达式)**2+cos(表达式)**2=1的处理办法,即遇到项的sin(表达式)的次数大于2,则去寻找cos(表达式)次数减2后其他部分与之前的相同,则可以考虑合并处理。

整体架构UML图如下

第三次作业后的总体架构图如下。

 

复杂度分析

表格太长可直接跳过看总结

HW_1

代码规模

使用statistic插件进行分析。

Source FileTotal LinesSource Code linesSource Code Lines[%]Comment LinesComment Lines[%]Blank LinesBlank Lines[%]
Add.java 9 8 0.8888888888888888 0 0.0 1 0.1111111111111111
Alpha.java 14 11 0.7857142857142857 0 0.0 3 0.21428571428571427
Bracket.java 40 34 0.85 0 0.0 6 0.15
MainClass.java 55 48 0.8727272727272727 2 0.03636363636363636 5 0.09090909090909091
Mul.java 29 27 0.9310344827586207 0 0.0 2 0.06896551724137931
Num.java 19 15 0.7894736842105263 0 0.0 4 0.21052631578947367
Operator.java 21 17 0.8095238095238095 0 0.0 4 0.19047619047619047
Parser.java 129 121 0.937984496124031 0 0.0 8 0.06201550387596899
Simply.java 119 112 0.9411764705882353 0 0.0 7 0.058823529411764705
Sub.java 21 20 0.9523809523809523 0 0.0 1 0.047619047619047616
Total: 456 413 0.9057017543859649 2 0.0043859649122807015 41 0.08991228070175439

方法复杂度

说明

使用metrics reloaded插件进行分析。

在分析结果中可以看到ev, iv, v这几栏,分别代指基本复杂度(Essential Complexity (ev(G))、模块设计复杂度(Module Design Complexity (iv(G)))、Cyclomatic Complexity (v(G))圈复杂度。

 CogC(Cognitive Complexity):认知复杂度,它将一段代码被阅读和理解时的复杂程度,估算成一个具体数字。

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

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

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

methodCogCev(G)iv(G)v(G)
Add.Add(Operator, Operator) 0.0 1.0 1.0 1.0
Add.getResult() 0.0 1.0 1.0 1.0
Alpha.Alpha(String) 0.0 1.0 1.0 1.0
Alpha.getResult() 0.0 1.0 1.0 1.0
Bracket.Bracket(Operator) 0.0 1.0 1.0 1.0
Bracket.getExpr() 0.0 1.0 1.0 1.0
Bracket.getOp() 3.0 1.0 3.0 3.0
Bracket.getResult() 0.0 1.0 1.0 1.0
Bracket.getSize() 0.0 1.0 1.0 1.0
Bracket.isInBracket() 0.0 1.0 1.0 1.0
MainClass.main(String[]) 0.0 1.0 1.0 1.0
MainClass.preManage(String) 16.0 1.0 5.0 7.0
Mul.getResult() 11.0 1.0 5.0 5.0
Mul.Mul(Operator, Operator) 0.0 1.0 1.0 1.0
Num.getResult() 0.0 1.0 1.0 1.0
Num.getValue() 0.0 1.0 1.0 1.0
Num.Num(BigInteger) 0.0 1.0 1.0 1.0
Operator.getLeft() 0.0 1.0 1.0 1.0
Operator.getResult() 0.0 1.0 1.0 1.0
Operator.getRight() 0.0 1.0 1.0 1.0
Operator.Operator(Operator, Operator) 0.0 1.0 1.0 1.0
Parser.findAddOrSub(String) 11.0 1.0 8.0 9.0
Parser.findMul(String) 5.0 1.0 4.0 5.0
Parser.findPow(String) 5.0 1.0 4.0 5.0
Parser.getNumber(String, int) 5.0 1.0 4.0 5.0
Parser.parse(String) 50.0 11.0 12.0 12.0
Simply.getNumber(String) 6.0 1.0 5.0 6.0
Simply.getResult(TreeMap) 17.0 1.0 10.0 10.0
Simply.simple() 17.0 8.0 10.0 11.0
Simply.Simply(String) 0.0 1.0 1.0 1.0
Simply.splitExpression() 5.0 1.0 4.0 5.0
Sub.getResult() 4.0 1.0 3.0 3.0
Sub.Sub(Operator, Operator) 0.0 1.0 1.0 1.0
Total 155.0 50.0 97.0 106.0
Average 4.696969696969697 1.5151515151515151 2.9393939393939394 3.212121212121212

HW_2

代码规模

Source FileTotal LinesSource Code linesSource Code Lines[%]Comment LinesComment Lines[%]Blank LinesBlank Lines[%]
Add.java 9 8 0.8888888888888888 0 0.0 1 0.1111111111111111
Alpha.java 14 11 0.7857142857142857 0 0.0 3 0.21428571428571427
Bracket.java 73 65 0.8904109589041096 0 0.0 8 0.1095890410958904
Cos.java 19 17 0.8947368421052632 0 0.0 2 0.10526315789473684
FunctManage.java 77 67 0.8701298701298701 4 0.05194805194805195 6 0.07792207792207792
MainClass.java 71 54 0.7605633802816901 8 0.11267605633802817 9 0.1267605633802817
Mul.java 29 27 0.9310344827586207 0 0.0 2 0.06896551724137931
Num.java 19 15 0.7894736842105263 0 0.0 4 0.21052631578947367
Operator.java 21 17 0.8095238095238095 0 0.0 4 0.19047619047619047
Parser.java 141 133 0.9432624113475178 0 0.0 8 0.05673758865248227
SimpleTerm.java 127 114 0.8976377952755905 3 0.023622047244094488 10 0.07874015748031496
Simply.java 106 99 0.9339622641509434 0 0.0 7 0.0660377358490566
Sin.java 19 17 0.8947368421052632 0 0.0 2 0.10526315789473684
Sub.java 21 20 0.9523809523809523 0 0.0 1 0.047619047619047616
Sum.java 37 33 0.8918918918918919 1 0.02702702702702703 3 0.08108108108108109
Termfact.java 150 139 0.9266666666666666 1 0.006666666666666667 10 0.06666666666666667
Total: 933 836 0.8960342979635584 17 0.01822079314040729 80 0.0857449088960343

方法复杂度

methodCogCev(G)iv(G)v(G)
Add.Add(Operator, Operator) 0.0 1.0 1.0 1.0
Add.getResult() 0.0 1.0 1.0 1.0
Alpha.Alpha(String) 0.0 1.0 1.0 1.0
Alpha.getResult() 0.0 1.0 1.0 1.0
Bracket.Bracket(Operator) 0.0 1.0 1.0 1.0
Bracket.getExpr() 0.0 1.0 1.0 1.0
Bracket.getOp() 7.0 1.0 5.0 6.0
Bracket.getResult() 0.0 1.0 1.0 1.0
Bracket.getSize() 0.0 1.0 1.0 1.0
Bracket.isInBracket() 0.0 1.0 1.0 1.0
Bracket.splitBracket() 9.0 1.0 5.0 8.0
Cos.Cos(String) 0.0 1.0 1.0 1.0
Cos.getResult() 2.0 2.0 1.0 2.0
FunctManage.changeFunc(String) 9.0 1.0 6.0 6.0
FunctManage.countComma(String) 3.0 3.0 2.0 3.0
FunctManage.findEndPlace(String) 6.0 3.0 3.0 5.0
FunctManage.putFunct(String) 1.0 1.0 2.0 2.0
MainClass.main(String[]) 1.0 1.0 2.0 2.0
MainClass.preManage(String) 16.0 1.0 5.0 7.0
Mul.getResult() 11.0 1.0 5.0 5.0
Mul.Mul(Operator, Operator) 0.0 1.0 1.0 1.0
Num.getResult() 0.0 1.0 1.0 1.0
Num.getValue() 0.0 1.0 1.0 1.0
Num.Num(BigInteger) 0.0 1.0 1.0 1.0
Operator.getLeft() 0.0 1.0 1.0 1.0
Operator.getResult() 0.0 1.0 1.0 1.0
Operator.getRight() 0.0 1.0 1.0 1.0
Operator.Operator(Operator, Operator) 0.0 1.0 1.0 1.0
Parser.findAddOrSub(String) 11.0 1.0 8.0 9.0
Parser.findMul(String) 5.0 1.0 4.0 5.0
Parser.findPow(String) 5.0 1.0 4.0 5.0
Parser.getNumber(String, int) 5.0 1.0 4.0 5.0
Parser.makeBracket(String, int) 5.0 3.0 3.0 3.0
Parser.parse(String) 49.0 11.0 12.0 12.0
SimpleTerm.getNum(String) 6.0 1.0 5.0 6.0
SimpleTerm.getSum() 0.0 1.0 1.0 1.0
SimpleTerm.getTermfact() 0.0 1.0 1.0 1.0
SimpleTerm.getUnsignedTerm() 3.0 3.0 3.0 3.0
SimpleTerm.putCos(String) 2.0 1.0 3.0 3.0
SimpleTerm.putSin(String) 2.0 1.0 3.0 3.0
SimpleTerm.setTermfact() 0.0 1.0 1.0 1.0
SimpleTerm.SimpleTerm(String) 10.0 1.0 9.0 9.0
SimpleTerm.splitTerm(String) 6.0 1.0 5.0 6.0
Simply.getNumber(String) 6.0 1.0 5.0 6.0
Simply.getResult() 17.0 1.0 8.0 8.0
Simply.simple() 3.0 1.0 3.0 3.0
Simply.Simply(String) 0.0 1.0 1.0 1.0
Simply.splitExpression() 9.0 1.0 5.0 8.0
Sin.getResult() 2.0 2.0 1.0 2.0
Sin.Sin(String) 0.0 1.0 1.0 1.0
Sub.getResult() 4.0 1.0 3.0 3.0
Sub.Sub(Operator, Operator) 0.0 1.0 1.0 1.0
Sum.Sum(String[]) 0.0 1.0 1.0 1.0
Sum.toString() 11.0 1.0 8.0 8.0
Termfact.equals(Object) 3.0 3.0 5.0 7.0
Termfact.getCharpow(String, int) 2.0 1.0 3.0 3.0
Termfact.getCosMap() 9.0 1.0 5.0 5.0
Termfact.getSinMap() 9.0 1.0 5.0 5.0
Termfact.hashCode() 0.0 1.0 1.0 1.0
Termfact.setTermfact(int, int, int, HashMap, HashMap) 0.0 1.0 1.0 1.0
Termfact.toString() 21.0 1.0 13.0 13.0
Total 270.0 83.0 190.0 213.0
Average 4.426229508196721 1.360655737704918 3.1147540983606556 3.4918032786885247

HW_3

代码规模

Source FileTotal LinesSource Code linesSource Code Lines[%]Comment LinesComment Lines[%]Blank LinesBlank Lines[%]
Add.java 9 8 0.8888888888888888 0 0.0 1 0.1111111111111111
Alpha.java 14 11 0.7857142857142857 0 0.0 3 0.21428571428571427
Bracket.java 69 60 0.8695652173913043 2 0.028985507246376812 7 0.10144927536231885
Cos.java 18 15 0.8333333333333334 0 0.0 3 0.16666666666666666
FunctManage.java 35 31 0.8857142857142857 0 0.0 4 0.11428571428571428
MainClass.java 35 21 0.6 7 0.2 7 0.2
Mul.java 31 28 0.9032258064516129 0 0.0 3 0.0967741935483871
Num.java 19 15 0.7894736842105263 0 0.0 4 0.21052631578947367
Operator.java 21 17 0.8095238095238095 0 0.0 4 0.19047619047619047
Parser.java 233 209 0.8969957081545065 12 0.05150214592274678 12 0.05150214592274678
SimpleTerm.java 157 135 0.8598726114649682 11 0.07006369426751592 11 0.07006369426751592
Simply.java 107 98 0.9158878504672897 2 0.018691588785046728 7 0.06542056074766354
Sin.java 17 15 0.8823529411764706 0 0.0 2 0.11764705882352941
Sub.java 23 21 0.9130434782608695 0 0.0 2 0.08695652173913043
Sum.java 46 39 0.8478260869565217 4 0.08695652173913043 3 0.06521739130434782
Sum1.java 45 38 0.8444444444444444 4 0.08888888888888889 3 0.06666666666666667
Termfact.java 146 131 0.8972602739726028 5 0.03424657534246575 10 0.0684931506849315
Total: 1025 892 0.8702439024390244 47 0.045853658536585365 86 0.08390243902439025

方法复杂度

methodCogCev(G)iv(G)v(G)
Add.Add(Operator, Operator) 0.0 1.0 1.0 1.0
Add.getResult() 0.0 1.0 1.0 1.0
Alpha.Alpha(String) 0.0 1.0 1.0 1.0
Alpha.getResult() 0.0 1.0 1.0 1.0
Bracket.Bracket(Operator) 0.0 1.0 1.0 1.0
Bracket.getExpr() 0.0 1.0 1.0 1.0
Bracket.getOp() 7.0 1.0 5.0 6.0
Bracket.getResult() 0.0 1.0 1.0 1.0
Bracket.getSize() 0.0 1.0 1.0 1.0
Bracket.splitBracket() 9.0 1.0 5.0 8.0
Cos.Cos(Operator) 0.0 1.0 1.0 1.0
Cos.getResult() 2.0 2.0 1.0 2.0
FunctManage.countComma(String) 3.0 3.0 2.0 3.0
FunctManage.getFuncMap() 0.0 1.0 1.0 1.0
FunctManage.putFunct(String) 1.0 1.0 2.0 2.0
MainClass.main(String[]) 1.0 1.0 2.0 2.0
Mul.getResult() 11.0 1.0 5.0 5.0
Mul.Mul(Operator, Operator) 0.0 1.0 1.0 1.0
Num.getResult() 0.0 1.0 1.0 1.0
Num.getValue() 0.0 1.0 1.0 1.0
Num.Num(BigInteger) 0.0 1.0 1.0 1.0
Operator.getLeft() 0.0 1.0 1.0 1.0
Operator.getResult() 0.0 1.0 1.0 1.0
Operator.getRight() 0.0 1.0 1.0 1.0
Operator.Operator(Operator, Operator) 0.0 1.0 1.0 1.0
Parser.findAddOrSub(String) 11.0 1.0 8.0 9.0
Parser.findMul(String) 5.0 1.0 4.0 5.0
Parser.findPow(String) 5.0 1.0 4.0 5.0
Parser.getNumber(String) 5.0 1.0 4.0 5.0
Parser.getParm(String) 9.0 1.0 5.0 7.0
Parser.makeBracket(String, int) 4.0 4.0 4.0 5.0
Parser.parse(String) 51.0 11.0 12.0 12.0
Parser.parseFunc(String, ArrayList) 1.0 1.0 2.0 2.0
Parser.preManage(String) 15.0 1.0 5.0 6.0
Parser.setFuncMap(HashMap) 0.0 1.0 1.0 1.0
SimpleTerm.getNum(String) 6.0 1.0 5.0 6.0
SimpleTerm.getSum() 0.0 1.0 1.0 1.0
SimpleTerm.getTermfact() 0.0 1.0 1.0 1.0
SimpleTerm.getUnsignedTerm() 3.0 3.0 3.0 3.0
SimpleTerm.putCos(String) 4.0 1.0 5.0 5.0
SimpleTerm.putSin(String) 4.0 1.0 5.0 5.0
SimpleTerm.setTermfact() 0.0 1.0 1.0 1.0
SimpleTerm.SimpleTerm(String) 10.0 1.0 9.0 9.0
SimpleTerm.splitTerm(String) 6.0 1.0 5.0 6.0
Simply.getNumber(String) 6.0 1.0 5.0 6.0
Simply.getResult() 17.0 1.0 8.0 8.0
Simply.simple() 3.0 1.0 3.0 3.0
Simply.Simply(String) 0.0 1.0 1.0 1.0
Simply.splitExpression() 9.0 1.0 5.0 8.0
Sin.getResult() 2.0 2.0 1.0 2.0
Sin.Sin(Operator) 0.0 1.0 1.0 1.0
Sub.getResult() 4.0 1.0 3.0 3.0
Sub.Sub(Operator, Operator) 0.0 1.0 1.0 1.0
Sum.Sum(ArrayList) 0.0 1.0 1.0 1.0
Sum.toString() 17.0 2.0 9.0 9.0
Termfact.equals(Object) 3.0 3.0 5.0 7.0
Termfact.getCharpow(String, BigInteger) 2.0 1.0 3.0 3.0
Termfact.getCosMap() 9.0 1.0 5.0 5.0
Termfact.getSinMap() 9.0 1.0 5.0 5.0
Termfact.hashCode() 0.0 1.0 1.0 1.0
Termfact.setTermfact(BigInteger, BigInteger, BigInteger, HashMap, HashMap) 0.0 1.0 1.0 1.0
Termfact.toString() 19.0 1.0 12.0 12.0
Total 290.0 87.0 204.0 227.0
Average 4.53125 1.359375 3.1875 3.546875

总结

以上表格中标加粗字体的是原表格显示为红色的部分。

  • Parser.parse()方法认知复杂度、结构复杂度、模块设计复杂度、圈复杂度都较高,并且随着作业的迭代开发复杂度有所升高。究其原因,是为解决不同优先级运算的处理问题,使用了大量if...else...嵌套结构,导致结构复杂度增加;同时该方法依赖于Sin、Cos、Add、Sub、Mul等类,导致耦合度较高,模块复杂度较高;同时在调试过程中,可以明显感受到一次操作,多个步骤都需要调用该方法,对该方法的正确性依赖较高。

  • Termfact.toString()中需要分类处理,调用其他小函数,造成该方法的模块复杂度、圈复杂度较高。

总体来讲,对于第一单元的作业,我的架构能够满足第一次到第三次作业的扩展需求,总体来讲复杂度适中,由于是基于数据结构表达式树进行设计,相对类间嵌套递归下降,理解起来较为容易,但在设计过程中的部分设计结构复杂度较高,不符合开闭原则,debug难度较高的问题,有待进一步改善。

Bug分析

被hack掉的bug分析

  • HW_1

    • 化简过程中将结果中1*直接用replaceAll()替换掉了,没有考虑到81*x等的问题,造成了bug。

  • HW_2这次作业在提交通过中测后没有进行总结处理,互测及强测中出现了很多bug。

    • sin(0)=1,由于直接赋值了cos()类的相关代码,没有修改全。

    • Bracket拆分时没有考虑sin(),cos()中也有可能有+-的问题,直接用split('[+-]')进行拆分,造成错误。

    • 表达式,函数替换后没有进行连续符号的处理就进行后序分解了。

    • sin()中x*x要以x**2的形式输出。

    • 自定义函数替换过程中将未知数x,y,z替换成‘a’+i,造成98会被替换成参数。

      由于cos中有c,所以将其替换为‘u'+i对应的字符。

    • sin乘法两项中没有乘号。

  • HW_3

    • 化简时时使用正则匹配未考虑sin(-cos()+sin())的情况,使用了.*匹配括号中内容。

    • sum上下界使用int范围不够。

bug修改方法心得

  • 首先将所有hack点进行提取分析归类,分析错误原因,依次找出对应的修改办法。

  • 修改小技巧:使用? :可以省行;仅针对被hack点处理,可以省区不必要修改。

  • 根据修改方法进行分类,提交每次合并修复。

心得:减少bug的方法

总结来看,bug都是由于思虑不周而产生的。

  • 设计时理清设计思路:可以添加必要注释。

  • 多次仔细阅读题目要求,考虑分类设计样例进行测试,尽量覆盖全面。

心得体会

通过第一单元的学习,我对于面向对象的思想有了更进一步的理解,学习了如何将复杂的工程分解成小部分进行处理,高内聚低耦合,开闭原则,类与对象的区别及联系等。并且通过三次作业代码的迭代开发与测试,提升了代码能力以及发现错误测试错误的能力,并且在研讨课及讨论区交流分享的过程中知道了而更多的方法技巧。

总结来讲,首先需要认真分析问题,理清设计思路,再根据设计思想着手完成项目构建,完成后多次测试,增强项目的鲁棒性。

posted @ 2022-03-25 21:28  BessiePei  阅读(93)  评论(1编辑  收藏  举报