OO第一单元总结

OO第一单元总结

第一单元是关于表达式求导,共涉及三次迭代作业,在难度,复杂度,鲁棒性等均有升级。

 


 

第一次作业

分析

第一次作业难度较小,且不会出现WRONG FORMAT,因此可以大胆处理。先直接去掉空格来使输入变得简单。且由于因子只会出现幂函数和常数,因此我考虑用Hashmap将指数和系数对应,进行运算和化简。

层次分析

UML类图:

 OO第一单元总结_第1张图片

第一次作业为了后面的拓展性和架构,用了三个类,一个是主类Main,一个是整体的表达式Poly,一个是是表达式每项Item,层层递进,既符合表达式项的架构,也为后面的迭代预留了空间。

 

代码复杂度分析

Method ev(G) iv(G) v(G)
task.Item.Item(BigInteger,BigInteger) 1 1 1
task.Item.Item(String) 1 1 1
task.Item.cacul(String) 3 6 6
task.Item.getCof() 1 1 1
task.Item.getIndex() 1 1 1
task.Item.getType() 1 1 1
task.Item.output() 1 16 16
task.Item.setType(int) 1 1 1
task.Item.settype() 1 3 4
task.Main.main(String[]) 1 2 2
task.Poly.Poly() 1 1 1
task.Poly.addTerm(String) 3 3 3
task.Poly.derivate() 1 3 3
task.Poly.output() 4 6 7

整体来说,耦合度不高,但也存在局部较高的地方,比如task.Item.output(),这是因为这个在我设计是用来处理最后的Poly类,并将其转成字符串来将其输出,与其他方法耦合度较高。

反思

我优化是通过合并同类项并将正数输出到第一项,效果较好,同时在本次作业中架构比较简单,因此bug并不多。但还有许多地方需要注意,比如多个运算符,还有指数为0等情况,特别是许多同学在优化过程中,忘记最后如果结果为0需要特判输出。

但在我程序架构中,没有将Func抽象出来,直接用幂函数的指数和系数代表因子,可以说有点投机取巧,因此后面作业拓展遇到了不小麻烦,只好重构。

 

第二次作业

分析

第二次作业难度大了许多,而且开始出现WRONG FORMAT,因此需要特判。我判断WRONG FORMAT是通过枚举错误情况,但由于第二次作业不会出现空格错误,因此可以先直接去掉空格来使输入变得简单。

在第一次作业由于因子只会出现幂函数和常数,用Hashmap将指数和系数对应,进行运算和化简。但第二次作业中已经有了sin cos三角函数,因此用Hashmap难度变大了许多,因此在以后的作业中,我采用了Arraylist 来进行数据存储。同时函数已经有许多种了,因此我将函数抽象出来,设计了Func抽象类,然后设计了Sin Cos Power类继承,其他架构与第一次相似。

在分项时主要采用正则表达式,由于第二次作业因子形式比较固定,因此这种方法效果较好,但在第三次作业中这种方法很难发挥神威了,需要替换。

同时在互测过程中借鉴了同组同学代码的优点,将一些符号替换,来使处理复杂度降低。

层次分析

UML类图:

 OO第一单元总结_第2张图片

第二次作业同第一次,依旧设置了主类Main,其作用是读取字符串,简单处理后(比如替换和查错),并将其送进Poly类,由Poly类的方法将其转换成一个多项式,然后Poly类进行分项,将分后的项传入Item类构造项,Item类再引用抽象类Func的子类方法实现化简运算等。

求导时,只需调用Poly类的求导方法,这样就可以一直从上到下调用求导方法来实现目的。

 

代码复杂度分析

Method ev(G) iv(G) v(G)
task.Item.Item(String) 1 1 1
task.Item.addCof(BigInteger) 1 1 1
task.Item.addItem(String) 1 9 9
task.Item.cmp(Item) 4 3 4
task.Item.derivative() 4 3 4
task.Item.getCof() 1 1 1
task.Item.getDelist() 1 1 1
task.Item.getItem() 1 2 2
task.Item.getList() 1 1 1
task.Item.judge(String) 4 5 5
task.Item.separate(String) 1 2 2
task.Item.unit(String) 5 5 10
task.Main.check(String) 10 3 10
task.Main.main(String[]) 2 2 2
task.Main.replce(String) 1 2 3
task.Poly.Poly(String) 3 2 3
task.Poly.derivative() 1 3 3
task.Poly.res() 1 4 6
task.Poly.unit() 3 3 4
task.Poly.unitpoly() 6 9 11
task.function.Cos.Cos() 1 1 1
task.function.Cos.addIndex(BigInteger) 1 1 1
task.function.Cos.derivative() 2 3 3
task.function.Cos.getCof() 1 1 1
task.function.Cos.getDeFunc() 1 1 1
task.function.Cos.getFunc() 3 4 4
task.function.Cos.getIndex() 1 1 1
task.function.Cos.getType() 1 1 1
task.function.Cos.mulCof(BigInteger) 1 1 1
task.function.Cos.setFunc(String) 4 5 5
task.function.Power.Power() 1 1 1
task.function.Power.addIndex(BigInteger) 1 1 1
task.function.Power.derivative() 2 3 3
task.function.Power.getCof() 1 1 1
task.function.Power.getDeFunc() 1 1 1
task.function.Power.getFunc() 3 4 4
task.function.Power.getIndex() 1 1 1
task.function.Power.getType() 1 1 1
task.function.Power.mulCof(BigInteger) 1 1 1
task.function.Power.setFunc(String) 4 5 5
task.function.Sin.Sin() 1 1 1
task.function.Sin.addIndex(BigInteger) 1 1 1
task.function.Sin.derivative() 2 3 3
task.function.Sin.getCof() 1 1 1
task.function.Sin.getDeFunc() 1 1 1
task.function.Sin.getFunc() 3 4 4
task.function.Sin.getIndex() 1 1 1
task.function.Sin.getType() 1 1 1
task.function.Sin.mulCof(BigInteger) 1 1 1
task.function.Sin.setFunc(String) 4 5 5

由于在设计中需要从上到下的引用,因此耦合度较第一次作业高了一些,但总体情况还是较好的。

不过有些方法复杂度较高,比如task.Poly.unitpoly() task.Main.check(String)等,他们主要是用来处理字符串的,需要我程序中定义的一些静态变量,因此耦合度偏高。

 

反思

本次作业中WRONG FORMAT判断的不好,导致失了一些分,同时在优化过程中产生了一些不必要的bug,在互测过程中被hack出来。

在判断WF中,我采用的是枚举错误的方法,这种很难覆盖所有错误情况,因此失分也是情理之中。讨论区有许多同学提出边处理边判断的方法,符合架构,值得借鉴学习。同时在自己测试中,分为了几种情况爆破,将自己逻辑复杂度较高的部分集中爆破,测出了一些bug,并预测和查看了同组同学的代码较复杂的部分,自己的bug和再次构造的bug测了同屋的同学。

本次架构为第三次作业留了许多可以拓展的空间,这也使得第三次作业不需要重构。同时Poly Item Func类等单独处理自己需要处理的,通过引用即可,很好的体现了面向对象的思想。

 

第三次作业

分析

第三次作业难度又大了许多,而且由于表达式方式多变,因此会出现复杂WRONG FORMAT。我判断WRONG FORMAT是通过枚举错误情况,先判断是否是由空格引起,在判断是否是由于其他情况引起的。

在第二次作业由于sin cos三角函数中因子固定,处理难度不大,但在第三次作业中,因子嵌套,需要采用递归思想来构造。同时我仍然继承了第二次作业设计的Func抽象类,然后设计了Sin Cos Power类继承,并新加了Const Exp两个“类函数”来继承。

在分项时由于因子嵌套,很难再次采用大正则表达式直接分项。因此在第三次作业中我采取了有限状态机来进行分项。

同时在互测过程中借鉴了同组同学代码的优点,将一些符号替换,来使处理复杂度降低。

层次分析

UML类图:

OO第一单元总结_第3张图片

第三次作业架构与第二次类似,依旧设置了主类Main,其作用是读取字符串,简单处理后(比如替换和查错),并将其送进Poly类,由Poly类的方法将其转换成一个多项式,然后Poly类进行分项,将分后的项传入Item类构造项,Item类再引用抽象类Func的子类方法实现化简运算等。

求导时,只需调用Poly类的求导方法,这样就可以一直从上到下调用求导方法来实现目的。

而对于函数求导,需要借用相互引用,即Exp中引用的Poly类,来进行递归求导,最后采用字符串的形式拼接在一起输出。

代码复杂度分析

Method ev(G) iv(G) v(G)
task.Item.Item(String) 1 3 3
task.Item.addStrlist(String) 1 6 6
task.Item.derivative() 5 4 6
task.Item.getDestr() 1 1 1
task.Main.check(String) 13 2 13
task.Main.checkspce(String) 6 3 7
task.Main.main(String[]) 3 6 6
task.Poly.Poly(String) 1 2 2
task.Poly.addlist(String) 1 12 12
task.Poly.derivative() 1 3 4
task.Poly.getDestr() 1 1 1
task.Poly.replce(String) 1 1 1
task.factory.Factory.check(String) 1 6 6
task.factory.Factory.getConst(String) 1 1 1
task.factory.Factory.getCos(String) 1 1 1
task.factory.Factory.getExp(String) 1 1 1
task.factory.Factory.getFunc(String) 5 7 7
task.factory.Factory.getPower(String) 1 1 1
task.factory.Factory.getSin(String) 1 1 1
task.function.Const.Const(String) 1 1 1
task.function.Const.addIndex(BigInteger) 1 1 1
task.function.Const.derivative() 1 1 1
task.function.Const.getCof() 1 1 1
task.function.Const.getDeFunc() 1 1 1
task.function.Const.getFunc() 1 1 1
task.function.Const.getIndex() 1 1 1
task.function.Const.getType() 1 1 1
task.function.Const.mulCof(BigInteger) 1 1 1
task.function.Const.setFunc(String) 1 1 1
task.function.Cos.Cos(String) 1 1 1
task.function.Cos.addIndex(BigInteger) 1 1 1
task.function.Cos.check(String) 5 1 5
task.function.Cos.derivative() 2 4 4
task.function.Cos.getCof() 1 1 1
task.function.Cos.getDeFunc() 1 1 1
task.function.Cos.getFunc() 1 1 1
task.function.Cos.getIndex() 1 1 1
task.function.Cos.getType() 1 1 1
task.function.Cos.mulCof(BigInteger) 1 1 1
task.function.Cos.setFunc(String) 1 12 13
task.function.Exp.Exp(String) 1 2 2
task.function.Exp.addIndex(BigInteger) 1 1 1
task.function.Exp.derivative() 1 1 1
task.function.Exp.getCof() 1 1 1
task.function.Exp.getDeFunc() 1 1 1
task.function.Exp.getFunc() 1 1 1
task.function.Exp.getIndex() 1 1 1
task.function.Exp.getType() 1 1 1
task.function.Exp.mulCof(BigInteger) 1 1 1
task.function.Exp.setFunc(String) 1 1 1
task.function.Power.Power(String) 1 1 1
task.function.Power.addIndex(BigInteger) 1 1 1
task.function.Power.derivative() 2 3 3
task.function.Power.getCof() 1 1 1
task.function.Power.getDeFunc() 1 1 1
task.function.Power.getFunc() 1 1 1
task.function.Power.getIndex() 1 1 1
task.function.Power.getType() 1 1 1
task.function.Power.mulCof(BigInteger) 1 1 1
task.function.Power.setFunc(String) 2 3 4
task.function.Sin.Sin(String) 1 1 1
task.function.Sin.addIndex(BigInteger) 1 1 1
task.function.Sin.check(String) 5 1 5
task.function.Sin.derivative() 2 4 4
task.function.Sin.getCof() 1 1 1
task.function.Sin.getDeFunc() 1 1 1
task.function.Sin.getFunc() 1 1 1
task.function.Sin.getIndex() 1 1 1
task.function.Sin.getType() 1 1 1
task.function.Sin.mulCof(BigInteger) 1 1 1
task.function.Sin.setFunc(String) 1 12 13
task.unit.Poly2.Poly2(String) 1 1 1
task.unit.Poly2.getRes() 1 1 1
task.unit.Poly2.replce(String) 1 2 3

由于在设计中需要从上到下的引用,因此耦合度较第二次作业高了一些,但总体情况还是较好的,平均值甚至较第二次降了一些

不过有些方法复杂度较高,比如task.Main.check(String)等,他们主要是用来处理字符串的,需要我程序中定义的一些静态变量,因此耦合度偏高。

 

反思

本次作业架构比较复杂,因此没有怎么优化,性能分也得的不多,在借鉴了同学分享的优秀代码后,发现搜索和贪心都是很不错的优化思路。

在判断WF中,我采用的是枚举错误的方法,这种很难覆盖所有错误情况,因此失分也是情理之中。讨论区有许多同学提出边处理边判断的方法,符合架构,值得借鉴学习。同时在自己测试中,分为了几种情况爆破,将自己逻辑复杂度较高的部分集中爆破,测出了一些bug,并预测和查看了同组同学的代码较复杂的部分,自己的bug和再次构造的bug测了同屋的同学。

本次作业是在第二次作业上拓展而来,仍然很好的体现了面向对象思想,但部分类或方法之间的耦合度较高,这仍是我需要提高的地方。

 

测试Bug

三次作业难度呈明显上升趋势,随着工程量增大,潜在bug数也会增大,因此测试Bug是一个很重要的部分。

我测试主要采用两种办法:

  • 对自己逻辑复杂的地方进行集中爆破,这些地方很容易出现逻辑混乱的地方。

  • 对边界极端情况进行单独测试,保证自己没有遗漏特殊的地方。

测试同学时也主要采用上述方法。

 

总结

这一单元只是这个课程的开端,我们仍需要花很多功夫去提高,去真正地理解面向对象。

同时在checkstyle等工具下,强制改掉自己不好的编程习惯。

总的来说,通过自己设计和阅读同学优秀代码慢慢让自己感受到面向对象的思想,也有了一些面向对象的工程能力。

你可能感兴趣的:(OO第一单元总结)