第一次博客作业
(一)基于度量来分析自己的程序结构
第一次作业类图及度量:
Complexity metrics | |||
---|---|---|---|
Method | ev(G) | iv(G) | v(G) |
Main.main(String[]) | 1 | 1 | 1 |
PolyHashmap.add(BigInteger,BigInteger) | 1 | 3 | 3 |
PolyHashmap.coeMatch(String) | 1 | 2 | 2 |
PolyHashmap.coeMatch0(String) | 1 | 1 | 1 |
PolyHashmap.display() | 1 | 11 | 11 |
PolyHashmap.find(String,PolyHashmap) | 1 | 7 | 8 |
PolyHashmap.getNum(String) | 1 | 1 | 1 |
PolyHashmap.isEmpty(String) | 1 | 2 | 2 |
PolyHashmap.isValid(String) | 1 | 2 | 2 |
PolyHashmap.punFirst(String) | 2 | 1 | 2 |
PolyNode.getCoeff() | 1 | 1 | 1 |
PolyNode.getDegree() | 1 | 1 | 1 |
PolyNode.setCoeff(BigInteger) | 1 | 1 | 1 |
PolyNode.setDegree(BigInteger) | 1 | 1 | 1 |
Class | OCavg | WMC |
---|---|---|
Main | 1 | 1 |
PolyHashmap | 3.22 | 29 |
PolyNode | 1 | 4 |
通过分析类图,metrics图,我发现第一次作业中PolyHashmap类的平均循环复杂度和总循环复杂度稍高,尤其是它包含的方法find()和display()方法,紧密程度和循环度高,造成了这种情况,其他较为正常。
所以缺点在于我刚开始接触面向对象,所以还有着面向过程的思想,虽然分为三个类,但PolyHashmap包含了大量方法,包括find(),判断输入合法性并存取,display(),按格式输出内容,这些方法冗长而复杂,造成了程序耦合度和复杂度的增加,而优点在于使用了hashmap结构来化简合并同类项,其中PolyHashmap和PolyNode的不少方法在第二次作业中可以在加以改进后使用。
第二次作业类图及度量:
Complexity metrics | |||
---|---|---|---|
Method | ev(G) | iv(G) | v(G) |
Interpreter.find(String,PolyHashmap) | 1 | 12 | 13 |
Interpreter.find1(String) | 2 | 2 | 2 |
Interpreter.find2(String) | 2 | 2 | 2 |
Interpreter.find3(String) | 2 | 2 | 2 |
Interpreter.find4(String) | 2 | 2 | 2 |
Interpreter.find5(String) | 2 | 2 | 2 |
Interpreter.find6(String) | 2 | 2 | 2 |
Interpreter.find7(String) | 2 | 2 | 2 |
Interpreter.getNum(String) | 1 | 1 | 1 |
Interpreter.head(String) | 1 | 1 | 1 |
Interpreter.isEmpty(String) | 1 | 2 | 2 |
Interpreter.out() | 1 | 1 | 1 |
Interpreter.punFirst(String) | 3 | 2 | 3 |
Interpreter.replacenow(String,int) | 9 | 9 | 9 |
Main.main(String[]) | 1 | 2 | 2 |
PolyHashmap.add(BigInteger,BigInteger,BigInteger,BigInteger) | 1 | 2 | 2 |
PolyHashmap.change() | 5 | 5 | 6 |
PolyHashmap.cosderivation(PolyNode,PolyHashmap) | 1 | 1 | 1 |
PolyHashmap.derivation() | 3 | 5 | 6 |
PolyHashmap.display() | 4 | 10 | 17 |
PolyHashmap.poderivation(PolyNode,PolyHashmap) | 1 | 1 | 1 |
PolyHashmap.push(PolyNode) | 1 | 3 | 3 |
PolyHashmap.sinderivation(PolyNode,PolyHashmap) | 1 | 1 | 1 |
PolyNode.equals(Object) | 4 | 3 | 7 |
PolyNode.getCoeff() | 1 | 1 | 1 |
PolyNode.getCosdegree() | 1 | 1 | 1 |
PolyNode.getPodegree() | 1 | 1 | 1 |
PolyNode.getSindegree() | 1 | 1 | 1 |
PolyNode.hashCode() | 1 | 1 | 1 |
PolyNode.setCoeff(BigInteger) | 1 | 1 | 1 |
PolyNode.setCosdegree(BigInteger) | 1 | 1 | 1 |
PolyNode.setPodegree(BigInteger) | 1 | 1 | 1 |
PolyNode.setSindegree(BigInteger) | 1 | 1 | 1 |
Class | OCavg | WMC |
---|---|---|
Interpreter | 3.14 | 44 |
Main | 2 | 2 |
PolyHashmap | 4.5 | 36 |
PolyNode | 1.3 | 13 |
通过分析类图,metrics图,我发现第二次作业中程序总体耦合度较高,PolyHashmap类和Interpreter类的平均循环复杂度和总循环复杂度较高,尤其是PolyHashmap包含的display()方法以及Interpreter类的find()和replacenow()方法,紧密程度和循环度高。
所以优点在于继承了上一次作业中的hashmap结构来化简合并同类项,并且用自定义类作为key值并针对第一次的缺点增加了Interpreter类,相当于InputHandler,对输入进行判断处理再存入map。缺点在于正则表达式判断和存取的相关方法较为冗长而复杂,而且方法间的交互出现了疏忽,正如针对sin(x)^2+cos(x)^2=1的优化操作受存取操作的影响,出现了正确性问题,导致强测和互测出现bug。
第三次作业类图及度量:
Complexity metrics | |||
---|---|---|---|
Method | ev(G) | iv(G) | v(G) |
Constant.derivation() | 1 | 1 | 1 |
Constant.getCons() | 1 | 1 | 1 |
Constant.setCons(BigInteger) | 1 | 1 | 1 |
Constant.toString() | 1 | 1 | 1 |
CosX.derivation() | 1 | 4 | 4 |
CosX.getCosdeg() | 1 | 1 | 1 |
CosX.getExpression() | 1 | 1 | 1 |
CosX.setCosdeg(BigInteger) | 1 | 1 | 1 |
CosX.setExpression(Expression) | 1 | 1 | 1 |
CosX.toString() | 1 | 1 | 2 |
Expression.add(Terms) | 1 | 1 | 1 |
Expression.derivation() | 1 | 2 | 2 |
Expression.getTermsArrayList() | 1 | 1 | 1 |
Expression.setTermsArrayList(ArrayList
|
1 | 1 | 1 |
Expression.toString() | 3 | 2 | 3 |
FunX.derivation() | 1 | 4 | 4 |
FunX.getPodeg() | 1 | 1 | 1 |
FunX.setPodeg(BigInteger) | 1 | 1 | 1 |
FunX.toString() | 2 | 1 | 3 |
InputHandler.catchCos(String) | 1 | 2 | 2 |
InputHandler.catchSin(String) | 1 | 2 | 2 |
InputHandler.catchbegin(String) | 1 | 1 | 1 |
InputHandler.catchdeg(String) | 1 | 2 | 2 |
InputHandler.catchend(String) | 4 | 7 | 7 |
InputHandler.find1(String) | 2 | 2 | 2 |
InputHandler.find2(String) | 2 | 2 | 2 |
InputHandler.find3(String) | 2 | 2 | 2 |
InputHandler.find4(String) | 2 | 2 | 2 |
InputHandler.find5(String) | 2 | 2 | 2 |
InputHandler.find6(String) | 2 | 2 | 2 |
InputHandler.findgree(String) | 2 | 2 | 2 |
InputHandler.getNum(String) | 1 | 1 | 1 |
InputHandler.isEmpty(String) | 1 | 2 | 2 |
InputHandler.isExp() | 1 | 5 | 6 |
InputHandler.isFactor(Terms) | 1 | 9 | 9 |
InputHandler.out() | 1 | 1 | 1 |
InputHandler.punFirst(String) | 3 | 2 | 3 |
InputHandler.replacenow(String,int) | 8 | 8 | 8 |
InputHandler.setExp(String) | 1 | 1 | 1 |
Main.main(String[]) | 1 | 2 | 2 |
SinX.derivation() | 1 | 4 | 4 |
SinX.getExpression() | 1 | 1 | 1 |
SinX.setExpression(Expression) | 1 | 1 | 1 |
SinX.setSindeg(BigInteger) | 1 | 1 | 1 |
SinX.toString() | 1 | 1 | 2 |
Terms.add(Factors) | 1 | 1 | 1 |
Terms.addTerms(Terms,BigInteger,BigInteger) | 1 | 4 | 4 |
Terms.deletecons() | 1 | 3 | 3 |
Terms.derivation() | 7 | 7 | 10 |
Terms.isEmpty() | 1 | 1 | 1 |
Terms.toString() | 3 | 2 | 3 |
Class | OCavg | WMC |
---|---|---|
Constant | 1 | 4 |
CosX | 1.67 | 10 |
Expression | 1.6 | 8 |
FunX | 2.25 | 9 |
InputHandler | 2.9 | 58 |
Main | 2 | 2 |
SinX | 1.8 | 9 |
Terms | 3.5 | 21 |
通过分析类图,metrics图,我发现第三次作业中程序耦合度较第二次有所改善,运用了面向对象的思想进行设计,还建立了接口,合理分类,其中InputHandler类总循环复杂度较高,大部分方法数据正常,个别方法的紧密程度或循环度稍高。
所以优点在于平均循环复杂度和总循环复杂度相比于第二次作业要下降不少,并针对第二次的缺点和第三次作业特点,重新设计了类和方法,采取了ArrayList,Expression存Terms,Terms存Factors,使用Factor接口,使得不同类的因子存于同一list中,建立了嵌套联系,求导思路是递归,求Expression类的导数需要递归求导,Expression里还可以有项,项里还可能有因子Factor,Factor里还可能有Expression,一直循环下去直到表达式或项的Arraylist为空,判断是否合法也是递归。缺点在于表达式的递归判断和存取的相关方法较为复杂,导致InputHandler循环度较高,而且存取后是边求导,边输出,没有做好优化工作。
(二)分析自己程序的bug
第一次未通过的公测用例和被互测发现的bug较多,原因主要在于我的匆忙优化,display时没有打印0前面的+号,语句if (p == 1 && v.getCoeff().compareTo(i) >= 0) System.out.print("+"); 漏写了“=“号,导致不会输出”+“。
而第一次的bug还来自于自己对正则表达式的不熟练运用,应该加上^,才能实现从字符串开头开始匹配。
第二次的bug主要因为自己在优化过程时,没有仔细分析可能的情况,方法间的交互出现了疏忽,正如优化操作受存取操作时没有排除系数为0的项的影响,出现了正确性问题,导致强测和互测出现bug。
第三次作业,我被hack较多,但其实都来自于同一个bug,第三次求导中有很多嵌套调用,我对方法间的联系理解出现了疏忽,导致输出时格式有bug,出现了正确性问题,导致强测和互测出现bug。而这个bug出现在Terms的toString()方法里,应该在输出因子前后分别加上左括号和右括号。
(三)分析自己发现别人程序bug所采用的策略
我采用的策略是:在互测阶段,寻找别人的bug时,我首先使用自己在强测前即中测阶段,对自己的project所使用的测试样例来对别人的程序进行测试,会仔细看指导书的要求来构造,对指导书的边界样例进行总结,构造相关测试点,正如:第一次作业的格式问题。之后,我会仔细阅读room里其他人的代码,寻找潜在bug,找到后就构建相关测试样例。另外,还可以编写自动化测试,以及构建脚本文件等使测试更加快捷、全面。
(四)Applying Creational Pattern
这三次作业,我每次相对于上一次都有一定改进和重构。
第一次作业主要思维还是面向过程,复用性较差。设置了两个类,只是输入判断的方法和map的结构在第二次能继续使用。
第二次作业,我在第一次的基础上,保留了hashmap结构,并且用自定义类作为key值,并针对第一次的缺点增加了Interpreter类,对输入进行判断处理,提取出系数、x、sin(x)、cos(x)的指数等再存入map。
第三次作业,重构较多,重新设计了类和方法,采取了ArrayList结构,用Expression类存Terms,Terms类存Factors,使用Factor接口,使得不同类的因子,如幂函数FunX,三角函数SinX、CosX等类存于同一list中,建立了嵌套结构。每个类有自己的求导方法和toString方法,求导通过递归来一层一层获得所需值并输出。