OO第一单元作业总结

 前言

  本学期第一次接触面向对象的思想和编程。在第一单元的作业中,专注于求导,并试着用面向对象的方法来解决求导问题。

  三次求导作业,第一次作业重点是多项式求导,死二次作业在多项式求导的基础上增加了三角函数求导,第三次作业增加了括号嵌套的层层求导。不同于以往的编程训练,面向对象的开发每次的作业更注重结构设计,以便往后的迭代开发,为自己减少推倒重构的风险,减少开发难度。

 

一 基于度量来分析自己的程序结构和缺陷

第一次作业分析

  第一次作业主要有三个类组成,分别为Main,Derivative,Item类,UML结构图如下所示:

 

  Main类主要用来键盘输入和屏幕输出操作,并调用Derivative类进行输入处理,Item用于处理Derivative传入的多项式的各项底数和指数。

  在Derivative类中,难点在于表达式的分割,再次,我采用正则式来进行表达式分割。但是我用正则式的缺点在于产生了一个正则打天下的naive想法,结果就是很容易在处理较长的表达式时候极易爆栈,而且考虑情况也不很完全,一些边边角角的WRONG FORMAT!情况就无法很好地处理。在互测中也因此比较惨淡。

  互测中,阅读其他同学的代码,分开匹配表达式是很好的一种办法,我所在房屋里我认为比较好的一些匹配做法是:1.尽可能让每一个项都标准化,即将‘++’‘--’‘+-’‘-+’全部换为单运算符,标准化的表达式简化正则式的匹配、、书写;2.匹配错误情况,匹配到了除了合法字符以外的字符就返回错误;判断正确就把合法的空格,水平制表符统统吃掉(replaceall),这样就可以带着简短的表达式进入下一阶段的判断。

  下面是对方法复杂度的分析,第一次作业的实现功能较为简单,复杂度爆红即复杂度高的方法略少;

 

Methodev(G)iv(G)v(G)
Derivative.dealMyItem() 1.0 4.0 4.0
Derivative.Derivative(String) 1.0 7.0 7.0
Derivative.getMyItem() 1.0 3.0 3.0
Derivative.getSize() 1.0 1.0 1.0
Derivative.optimizeMyItem() 5.0 5.0 5.0
Derivative.optimizeOutput(String) 1.0 14.0` 14.0
Derivative.print() 1.0 7.0 7.0
Derivative.setMyItem(String) 1.0 2.0 2.0
Item.compressItem() 1.0 14.0 14.0
Item.getFactor() 1.0 1.0 1.0
Item.getFactor_d() 1.0 1.0 1.0
Item.getIndex() 1.0 1.0 1.0
Item.getIndex_d() 1.0 1.0 1.0
Item.getItem() 1.0 1.0 1.0
Item.mergeMyItem(Item) 1.0 1.0 1.0
Item.setFactor() 1.0 3.0 3.0
Item.setFactor_d() 1.0 1.0 1.0
Item.setIndex() 1.0 2.0 3.0
Item.setIndex_d() 1.0 1.0 1.0
Item.setItem(String) 1.0 1.0 1.0
Main.main(String[]) 1.0 1.0 1.0
Total 25.0 72.0 73.0
Average 1.1904761904761905 3.4285714285714284 3.4761904761904763

第二次作业分析

  第二次作业收到之后,发现增加了三角函数求导和三角函数幂函数形式的求导,当时就估计很有可能在第三次作业中增加括号嵌套的求导,这就会使得正则式匹配不再好使,因此毅然决定推倒重写,在第二次作业中不再使用正则式进行匹配;先上UML结构图:

 

  可以发现本次作业结构十分复杂,当时咨询了一位软院大佬以后,按照他的建议,严格按照参考书,将匹配分为因子(Factor)项(Item)表达式(Expression)三级数据结构,最底层的因子又下辖幂函数,三角函数,常数的匹配方法,(据该大佬说我们的作业有点淡淡的编译原理文法分析的气息),在此不再赘述。对应三级数据结构的就是对应三级数据结构的三级分析方法类,首先将几个三级分析类都要使用的方法扔进最顶层的分析方法类,三级分析类就直接继承到了该顶层类,这也是我第一次在作业中应用继承的方法。其余如IO部分等和第一次作业保持一致。

  这一次作业给我的指导和启发就在于让我学到了这种数据结构类+分析方法类结合的编程方法,对于表达式的判断也就不再需要在最顶层判断,而是分散到各级的类当中处理,符合情况就返回匹配到的项,因子,否则就Null,这就使得表达式的匹配和分割可以比较愉快的进行下去。这样编程的整体构造方法就比第一次作业更加软工了一些。

  这一次作业几乎是完全推倒重来,因此bug众多也是难以避免的,指导书中对于表达式的表述对于第一项可以带一个正负号,包括第一因子为常数且值为1则可以省略该常数因子或表示为证号开头的形式,这些特殊情况我的处理做的不太好,问题集中在ExpressionAnalyser即表达式分析类中,特判第一项和正常匹配后续项数的方式导致行数和bug众多,在互测中也因为这个类的书写问题被打爆,值得庆幸的就是问题都是出在该类方法,就尝试修复该类,结果修复环节一改就超60行,只能在bug修复中将首项和后续项判断方法合并进行,终于一次性扫光了所有的互测中的bug。

  第二次作业的三级结构,就像摊大饼,很多方法就摊开了,因此复杂度尚可,当然,以后的书写中将会考虑使用Pakage将各级进行包装,否则目录中的众多类方法还真是令人吃不消。下面是方法复杂度的分析

 

Methodev(G)iv(G)v(G)
SinXAnalyser.analyse(String,int) 5.0 8.0 9.0
SinX.toString() 2.0 1.0 2.0
SinX.sinxD(SinX) 3.0 3.0 3.0
SinX.SinX(BigInteger) 1.0 1.0 1.0
SinX.SinX() 1.0 1.0 1.0
SinX.getIndex() 1.0 1.0 1.0
SinX.combine(SinX) 1.0 1.0 1.0
PowerFunctionAnalyser.analyse(String,int) 4.0 4.0 4.0
PowerFunction.toString() 2.0 1.0 2.0
PowerFunction.PowerFunction(BigInteger) 1.0 1.0 1.0
PowerFunction.powerD(PowerFunction) 2.0 2.0 2.0
PowerFunction.combine(PowerFunction) 1.0 1.0 1.0
Main.main(String[]) 1.0 4.0 4.0
ItemAnalyser.analyse(String,int) 4.0 4.0 4.0
Item.toString() 1.0 2.0 3.0
Item.numOfItem() 1.0 1.0 1.0
Item.mult(Factor) 10.0 10.0 10.0
Item.getFactor(int) 1.0 1.0 1.0
IntegerAnalyser.analyse(String,int) 4.0 4.0 14.0
FactorAnalyser.analyse(String,int) 9.0 9.0 9.0
ExpressionAnalyser.analyse(String,int) 9.0 6.0 12.0
Expression.printD() 1.0 4.0 4.0
Expression.print() 1.0 2.0 2.0
Expression.derivation() 4.0 9.0 10.0
Expression.better() 5.0 6.0 6.0
Expression.add(Item) 1.0 1.0 1.0
CosXAnalyser.analyse(String,int) 5.0 8.0 9.0
CosX.toString() 2.0 1.0 2.0
CosX.cosxD(CosX) 3.0 3.0 3.0
CosX.CosX(BigInteger) 1.0 1.0 1.0
CosX.CosX() 1.0 1.0 1.0
CosX.combine(CosX) 1.0 1.0 1.0
ConstFactor.toString() 1.0 1.0 1.0
ConstFactor.ConstFactor(BigInteger) 1.0 1.0 1.0
ConstFactor.combine(ConstFactor) 1.0 1.0 1.0
Analyser.skipSpace(String,int) 1.0 2.0 3.0
Analyser.setIndex(int) 1.0 1.0 1.0
Analyser.nextChar(String,int) 1.0 2.0 2.0
Analyser.getIndex() 1.0 1.0 1.0
Total 96.0 112.0 136.0
Average 2.4615384615384617 2.871794871794872 3.4871794871794872

 

第三次作业分析

  第三次作业果然上了表达式的嵌套,有了第二次作业打下的结构基础和匹配基础储备,这就稍微容易,线上UML结构图:

 

  本次作业有了嵌套,嵌套主要是三角函数类型的嵌套,和幂函数底数的嵌套,因此同样采用三级结构的同时,因此在处理中专门针对这两个特点,遇到三角函数前括号,前括号就切割字符串,采用递归但不回溯的办法继续匹配括号内的内容。本次作业的处理思想和实现最后看起来也没那么难以进行,但是在实际作业中仍然花了很多时间不断尝试,以至于几乎是压周二晚的线提交作业,很大程度可能是我一直以来对于递归的不熟悉和畏惧,C语言时如此,汇编语言时也如此,这次大量的调试中,看着递归层层运行和不断debug对于递归的处理也是熟悉了很多。

  本次作业的缺陷是对于整个表达式的匹配识别中开了一些天窗,即使用if特判一些情况,并没有很好地将所有情况的判断分散到三级架构中进行,这在一二次作业中不涉及递归运行还良好,在本次作业中这些通过if特判开天窗判断的办法就带来了一些bug,这就使得我带着一些已知的bug进入了强测中。

  以下是方法复杂度分析:

Methodev(G)iv(G)v(G)
VarFactor.VarFactor(Base,BigInteger) 1.0 1.0 1.0
VarFactor.VarFactor(Base) 1.0 1.0 1.0
VarFactor.print() 1.0 4.0 4.0
VarFactor.isIndexZero() 1.0 1.0 1.0
VarFactor.derivation() 1.0 1.0 1.0
SinXAnalyser.analyse(String,int) 5.0 5.0 6.0
SinX.SinX(Expression) 1.0 1.0 1.0
SinX.print() 1.0 1.0 1.0
SinX.derivation() 1.0 1.0 1.0
Main.main(String[]) 1.0 6.0 6.0
ItemAnalyser.analyse(String,int) 5.0 5.0 10.0
Item.print() 1.0 5.0 5.0
Item.mult(Factor) 1.0 4.0 4.0
Item.mult(BigInteger) 1.0 1.0 1.0
Item.isConst() 1.0 1.0 1.0
Item.derivation() 2.0 4.0 5.0
IntegerAnalyser.analyse(String,int) 4.0 4.0 14.0
FactorAnalyser.analyse(String,int) 7.0 8.0 8.0
Factor.print() 1.0 1.0 1.0
Factor.derivation() 1.0 1.0 1.0
ExpressionAnalyser.analyse(String,int) 8.0 8.0 15.0
Expression.print() 1.0 4.0 4.0
Expression.isConst() 2.0 2.0 2.0
Expression.derivation() 1.0 2.0 2.0
Expression.add(Item) 1.0 1.0 1.0
Expression.add(Expression) 1.0 1.0 1.0
CosXAnalyser.analyse(String,int) 5.0 5.0 6.0
CosX.print() 1.0 1.0 1.0
CosX.derivation() 1.0 1.0 1.0
CosX.CosX(Expression) 1.0 1.0 1.0
ConstFactor.print() 1.0 1.0 1.0
ConstFactor.getVal() 1.0 1.0 1.0
ConstFactor.ConstFactor(BigInteger) 1.0 1.0 1.0
BaseAnalyser.analyse(String,int) 10.0 10.0 10.0
Base.print() 1.0 1.0 1.0
Base.derivation() 1.0 1.0 1.0
Analyser.skipSpace(String,int) 1.0 2.0 3.0
Analyser.skipExp(String,int) 2.0 3.0 7.0
Analyser.setIndex(int) 1.0 1.0 1.0
Analyser.nextChar(String,int) 1.0 2.0 2.0
Analyser.getIndex() 1.0 1.0 1.0
Total 81.0 106.0 136.0
Average 1.975609756097561 2.5853658536585367 3.317073170731707

二、基于Metrics度量分析程序结构

  下面附上基于CK标准度量分析程序结构:

  第一次作业

  第二次作业

  第三次作业

  

 

posted @ 2019-03-27 21:54  SkyWalkerSkyWalker  阅读(137)  评论(0编辑  收藏  举报