OO第一单元总结——表达式求导

OO第一单元总结——表达式求导

第一次作业

第一次作业较为简单,即对幂函数进行求导即可,也不需要判断表达式的合法性。需要注意的点为数可能很大,需要转换为BigInteger,其次常数要输出0。然后就用面向过程的思维写了大正则,一Main到底,然后使用HashMap便于化简。

**(1)基于度量来分析自己的程序结构 **

OO第一单元总结——表达式求导_第1张图片

类很少,方法都在MainClass里面调用。

Method ev(G) iv(G) v(G)
c.MainClass.main(String[]) 3 6 6
c.MainClass.makeMap(HashMap,Matcher) 5 8 11
c.MainClass.printBig(BigInteger,BigInteger) 8 7 14
Class OCavg WMC
c.MainClass 9 27

由上表,可看出在处理字符串和输出字符串的方法的基本复杂度很高,代码不易于维护和理解,圈复杂度较高,代码难于测试和维护。

唯一的优点就是比较短。

**(2)分析自己程序的bug **

公测前发现当求导为0时未输出,互测未发现bug。bug原因在于HashMap容器不包含元素,因为value为0的被remove,所以没有输出。

**(3)分析自己发现别人程序bug所采用的策略 **

写了一个python程序来生成测试用例,但没有写对拍程序,在找bug时就用生成的数据输入,找bug,发现两个人的bug,还有一人未发现。虽然这种方法属于广撒网,但其实不好捞鱼。因为生成的数据并不能涵盖所有情况,有的同学就x+x算错,你可能就生成不出来。

第二次作业

第二次作业中增加了三角函数,而且需要判断输入表达式是否合法,但不会因为空白字符而WORNG FORMAT!因为三角函数的内容较为简单,所以在第一次作业的基础上创建了一个类记录每一项幂函数、三角函数的指数。

**(1)基于度量来分析自己的程序结构 **

OO第一单元总结——表达式求导_第2张图片

新建一个类Item记录每一项的幂函数和三角函数的指数,并作为ConcurrentHashMap的key值,来合并化简表达式。

Method ev(G) iv(G) v(G)
c.Item.Item(BigInteger,BigInteger,BigInteger) 1 1 1
c.Item.equals(Object) 3 4 6
c.Item.getIndexCos() 1 1 1
c.Item.getIndexSin() 1 1 1
c.Item.getIndexX() 1 1 1
c.Item.hashCode() 1 1 1
c.Item.printIndex(BigInteger) 3 11 16
c.MainClass.dealsinMap(ConcurrentHashMap) 1 7 7
c.MainClass.diff(ConcurrentHashMap,BigInteger,BigInteger,BigInteger,BigInteger) 3 3 5
c.MainClass.main(String[]) 4 8 8
c.MainClass.makeMap(ConcurrentHashMap,Matcher) 1 15 16
c.MainClass.printBig(BigInteger,Item) 1 1 1
c.MainClass.putMap(ConcurrentHashMap,Item,BigInteger) 4 3 4
Class OCavg WMC
c.Item 3.14 22
c.MainClass 6.33 38

由上表,可见第二次作业较第一次作业基本复杂度有降低,但部分方法模块设计复杂度变得很高,因为被其他模块多次调用,耦合度变得较高。

**(2)分析自己程序的bug **

在互测时被发现了bug,原因是在MainClass.dealsinMap中化简时忽略了HashMap不是多线程,在遍历key值时,同时移除了某些key,所以抛出了异常。所以后来上网查了一下,ConcurrentHashMap支持多线程,HashMap不支持。

**(3)分析自己发现别人程序bug所采用的策略 **

写了一个python程序来生成测试用例,但没有写对拍程序,在找bug时就用生成的数据输入,找bug,发现了一个人的bug,但是是WORNG FORMAT,所以无法hack,还有一个人在指数边界出错。互测应该是让我们看同学的代码来找bug,感觉丧失了意义。

第三次作业

第三次作业难度陡升,三角函数允许嵌套因子,还有表达式因子,所以无法写出一个大正则来匹配,所以重构了。使用递归的方法来求导。

OO第一单元总结——表达式求导_第3张图片

PolyCheck检查表达式的合法性,主要包括空白符,+-号;给每一种因子建立一种类继承自Factor;Poly就处理分割表达式。没有化简。

Method ev(G) iv(G) v(G)
Constant.Constant() 1 1 1
Constant.Constant(String) 1 1 1
Constant.derivation() 1 1 1
Constant.getString() 1 1 1
Constant.valid(String) 2 1 2
Cos.Cos() 1 1 1
Cos.Cos(String) 1 4 4
Cos.derivation() 3 5 7
Cos.getString() 1 1 1
Cos.valid(String) 2 1 2
Factor.Factor() 1 1 1
Factor.derivation() 1 1 1
Factor.getLength() 1 1 1
Factor.getString() 1 1 1
Factor.setString(String) 1 1 1
Factor.valid(String) 1 1 1
Main.main(String[]) 1 7 7
Nest.Nest() 1 1 1
Nest.Nest(String) 1 3 3
Nest.derivation() 1 1 1
Nest.getString() 1 1 1
Nest.valid(String) 2 1 2
Poly.Poly(String) 1 1 1
Poly.derivation() 1 12 16
Poly.derivation2(ArrayList ) 1 4 5
Poly.inset(String) 6 1 6
Poly.valid(String) 6 1 6
PolyCheck.PolyCheck() 1 1 1
PolyCheck.checkAgain(String) 5 3 5
PolyCheck.checkSign(String) 2 1 2
PolyCheck.checkSpace(String) 8 2 8
PolyCheck.replaceOp(String) 1 1 1
PolyCheck.replaceSpace(String) 1 1 1
Power.Power() 1 1 1
Power.Power(String) 1 3 3
Power.derivation() 3 4 7
Power.getString() 1 1 1
Power.valid(String) 2 1 2
Sin.Sin() 1 1 1
Sin.Sin(String) 1 4 4
Sin.derivation() 3 5 7
Sin.getString() 1 1 1
Sin.valid(String) 2 1 2
Class OCavg WMC
Constant 1.2 6
Cos 2.8 14
Factor 1 6
Main 5 5
Nest 1.4 7
Poly 5.4 27
PolyCheck 3 18
Power 2.6 13
Sin 2.8 14

第三次作业的平均基本复杂度、模块设计复杂度、圈复杂度较第二次作业都有降低。但是Poly.derivaton的复杂度较其他方法高,因为一直在循环调用其他方法。

**(2)分析自己程序的bug **

在强测和互测时被测出了bug,在Poly.derivation2(ArrayList )中,原因是给每一项求导时忽视了项前的符号,一直用+号连接。忽略这个bug是由于前两次作业一直使用HashMap保存系数,所以不需要考虑项之间的符号连接。但在第三次作业中,项与项之间通过+-号连接,这也是分割表达式的依据,传给Poly.derivation2(ArrayList )的也只是因子,忘记前面的+-号。后来更正的时候,Poly.derivation2(ArrayList )返回字符串时外面加一个括号也可以有效避免这个问题。

**(3)分析自己发现别人程序bug所采用的策略 **

写了一个python程序来生成测试用例,和对拍程序。但是,对拍写得不太对,只能区分特别明显的错误。发现了一个人的bug,但是还有其他人的bug未发现。因为这次表达式的复杂性,若只生成数据,肉眼是很难发现错误的。我觉得在互测方面,我还是得下点功夫。

应用对象创建模式

第一次作业主要是面向过程编程,可以将每一项创建一个对象,在对其求导。第二次作业在第一次作业的基础上添加了Item类,记录每一项的幂函数和三角函数的指数。第三次作业重构了,对每一种因子都创建了一个类,并继承自Factor类;PolyCheck检查表达式的合法性,主要包括空白符,+-号;Poly就分割表达式求导。

每一单元的作业的难度会逐渐提升,所以在第一次作业时就应该想好怎么创建对象,留一些余地扩展,以免给后面的作业增添太多压力,这样也比较符合实际。

对比和心得体会

对比优秀设计代码,我的设计明显还不够面向对象,也不够简洁。虽然我在前两次作业时较为轻松,但在第三次作业时几乎相当于重写了,若是第一次就想好了,之后也不会这么痛苦。

所以面向对象是关键,在对象改变时,添加几个类几个方法即可,不需要怎么改变结构,但面向过程即是,对象一旦改变,过程完全改变。

而且由于“一个人”设计代码,总会有遗漏的方面,而且常常难以发现,所以怎么构造测试样例也是一个关键。

希望在下次作业中,能考虑全面,而且能面向对象设计代码。

你可能感兴趣的:(OO第一单元总结——表达式求导)