OO第一次博客作业

引言:

面向对象程序设计课程第一阶段的三次作业已经结束。这个阶段的三次作业均是关于多项式求导,难度逐次递增,项目需要实现的功能逐渐丰富。本文按各次作业划分版块,每个版块主要以代码设计程序度量分析bug分析三个方面来展开此篇博客的内容,其中bug分析包括对自己程序的分析以及在互测中发现的问题。最后谈点自己在完成这阶段作业时的收获。

第一次作业:

作业简介:

输入的多项式含有幂函数变量项、常数项;求导涉及带系数幂函数求导法则。

代码设计:

下图是第一次作业的设计思路:

  • 构建正则表达式:
    先构造项的正则表达式,再由项的正则表达式构建多项式的正则表达式。实现了对整行输入的匹配。
  • 判断合法后处理输入方便提取项:
    在构思解题思路时,想通过加号作为分隔符分隔每项。最后形成的解决方案如下:
    • 第一步:用单个 + 或 - 符号替换诸如 -- , +- 等这样重复的运算符号;
    • 第二步:用 +- 符号替换 - 符号;再用 ^ 替换 ^+,从而实现可以用加号分隔每项,并且避免了幂函数正指数的 + 对分割产生的影响。分隔出的字符串存下它的系数和指数。
  • 求导:
    运用指导书给定的求导法则,对每项进行求导,更新每项的系数和指数。
  • 输出前的处理:
    在项这个类里重写toString(),对系数为0,1;指数为0,1的特殊进行处理;
    在最后输出环节调用项的toString()来构建最后输出的多项式。特别的,如果所有项中含系数为正数的项,那么最后输出的第一项的系数一定为正数。

本次作业的类图

度量分析:

method ev(G) iv(G) v(G)
work.ExtractItems.extract(String) 3.0 12.0 12.0
work.Item.getCoe() 1.0 1.0 1.0
work.Item.getIndex() 1.0 1.0 1.0
work.Item.Item() 1.0 1.0 1.0
work.Item.setCoe(BigInteger) 1.0 1.0 1.0
work.Item.setIndex(BigInteger) 1.0 1.0 1.0
work.Item.toString() 10.0 10.0 10.0
work.ProcessInput.removeDuplicateSymbol(String) 1.0 1.0 1.0
work.ProcessInput.removeSpace(String) 1.0 1.0 1.0
work.ProcessInput.segmentItem(String) 1.0 1.0 1.0
work.WorkBegin.checkIllegalNum(String) 2.0 1.0 2.0
work.WorkBegin.isCorrect(String) 1.0 1.0 1.0
work.WorkBegin.main(String[]) 1.0 3.0 3.0
work.WorkBegin.printList(ArrayList) 6.0 10.0 11.0
Total 31.0 45.0 47.0
Average 2.2142857142857144 3.2142857142857144 3.357142857142857
class OCavg WMC
work.ExtractItems 10.0 10.0
work.Item 2.5 15.0
work.ProcessInput 1.0 3.0
work.WorkBegin 4.25 17.0
Total 45.0
Average 3.2142857142857144 11.25

复杂度过高原因分析:

因为自己的思路是通过 + 分隔每项,实现这点需要对合法输入进行大量处理,而处理函数单独开在一个字符串处理类中,导致提取项方法间的耦合度过高。
WorkBegin类中的main()函数在设计时,被当作整个流程的调度者,其复杂度也过高。
对于字符串输出,此次作业未专门新建类,直接塞在WorkBegin类中,回想起来,当时的做法非常不合理。

Bug分析:

此次自己程序出现的bug:

这次在公测中未被测出bug。在互测环节,因为系数互为相反数,指数相同项的存在,处理字符串时,chatAt()方法对一个空的字符串进行了访问,因此被hack了一个同质bug。

互测时发现的问题:

可能是因为接触java时间不长的原因,很多人都没有进行异常处理,导致本地用控制台结束符可以使程序奔溃(当然第一次提交不上这个样例)。其他方面,有部分人用 \s 处理空白字符,而导致输入出现\f等一些不可见字符时会输出错误。

第二次作业

作业简介:

相较于第一次作业要求,项的种类增加了三角函数;求导法则增加了乘法求导法则。

代码设计:

此次设计代码时,未对一些在构思思路时已经意识到的问题想出解决方案,譬如因子求导结果如何传给项、项的求导结果如何传给多项式,直接写代码,最后导致在周一出现了几乎算重构代码似的局面。
最后,对于求导结果传递的问题,想出的解决办法是:因子求导后传给项对象一个新实例化的项,项对象维护一个项的list,最后将这个list传给多项式。
此次作业,对于因子使用了继承。三角函数因子,幂函数因子都继承一个抽象类因子。通过继承和多态增加了代码的易读性和可维护性。
而因sin函数和cos函数求导和输出的行为差别较大,将其分开定义成类。最后形成多项式-项-因子的层级式结构,高层对象都有底层对象的list成员变量。

本次作业的类图:

度量分析:

class OCavg WMC
work.CosFactor 2.6666666666666665 8.0
work.Factor 1.0 3.0
work.FormatErrorException 1.0 1.0
work.Item 3.0 27.0
work.Poly 5.857142857142857 41.0
work.PowerFactor 2.6666666666666665 8.0
work.SinFactor 2.6666666666666665 8.0
work.WorkBegin 1.0 1.0
Total 97.0
Average 3.2333333333333334 12.125
method ev(G) iv(G) v(G)
work.CosFactor.CosFactor(BigInteger) 1.0 1.0 1.0
work.CosFactor.derivate() 1.0 4.0 4.0
work.CosFactor.toString() 3.0 3.0 3.0
work.Factor.Factor(BigInteger) 1.0 1.0 1.0
work.Factor.getIndex() 1.0 1.0 1.0
work.Factor.setIndex(BigInteger) 1.0 1.0 1.0
work.FormatErrorException.FormatErrorException() 1.0 1.0 1.0
work.Item.Derivate() 4.0 3.0 4.0
work.Item.equals(Item) 3.0 2.0 3.0
work.Item.extractItem(String) 1.0 9.0 9.0
work.Item.getCoe() 1.0 1.0 1.0
work.Item.getFa(int) 1.0 1.0 1.0
work.Item.getFListSize() 1.0 1.0 1.0
work.Item.Item(String) 1.0 1.0 1.0
work.Item.setCoe(BigInteger) 1.0 1.0 1.0
work.Item.toString() 2.0 5.0 6.0
work.Poly.checkIllegalNum() 3.0 1.0 3.0
work.Poly.creatItemList() 3.0 3.0 5.0
work.Poly.derivateAndMerge() 7.0 9.0 10.0

复杂度过高原因分析:

本次作业检查合法性采用了先进行静态分析,再递归下降检查合法性的方法,使的检查合法性函数的复杂度下降了一些。
由于要对输出的长度进行优化,在多项式类中定义了很多合并,分解的化简方法,导致多项式类的复杂度过高。

Bug分析:

自己的问题:

此次因对指导书中三角函数格式合法性的理解有误,导致强测和互测的场面十分惨烈。

互测时的感想:

此次互测中,很多人做了对输入异常的处理,检查字符串合法性的方法也变得灵活了很多。但是由于在构建正则表达式时考虑得不太充分,对于有些简单的错误输入,一些同学的代码不能判断其格式错误。

第三次作业:

作业简介:

引入了多项式因子、嵌套因子;求导法则增加了复合函数的求导法则。

代码设计:

设计模式:工厂模式
阅读过课程组分享的第二次作业优秀代码,见识到了一些可应用在此类作业的设计模式。在第三次作业,我运用了工厂模式,在项实例化因子对象时,直接将因子的信息传递给FactorFactory,工厂自动返回具体的对象。
解决嵌套而导致运行超时的问题
此次作业的第一版本的代码设计得非常糟糕,处理嵌套层数多的表达式因子时,譬如外层有29层括号的x时,程序运行会超时。
为了解决嵌套而导致运行超时的问题,我这次作业的解决办法是在多项式实例化项之前,将可以去除的括号全部去除。

本次作业的类图:

度量分析:

class OCavg WMC
error.WrongFormatException 1.0 1.0
error.WrongIndexException 1.0 1.0
item.factor.CosFactor 4.25 17.0
item.factor.ExpFactor 2.8 14.0
item.factor.FactFactory 6.0 6.0
item.factor.Factor 1.0 3.0
item.factor.PowerFactor 3.0 9.0
item.factor.SignNum 1.0 3.0
item.factor.SinFactor 4.25 17.0
item.poly.Poly 4.375 35.0
item.term.Term 4.8 48.0
match.CheckExp 4.2 21.0
match.CheckIllegalIndex 3.0 3.0
match.CheckSpace 4.0 4.0
process.ProcessString 1.0 1.0
WorkBegin 1.0 1.0
Total 184.0
Average 3.5384615384615383 11.5
method ev(G) iv(G) v(G)
WorkBegin.main(String[]) 1.0 2.0 2.0
process.ProcessString.deleteOperator(String) 1.0 1.0 1.0
match.CheckSpace.check(String) 4.0 1.0 4.0
match.CheckIllegalIndex.check(String) 3.0 2.0 3.0
match.CheckExp.checkPurePoly(String) 2.0 1.0 2.0
match.CheckExp.checkPureFactor(String) 2.0 1.0 2.0
match.CheckExp.checkNest(String,int) 8.0 17.0 19.0
match.CheckExp.CheckExp(String) 1.0 1.0 1.0
match.CheckExp.checkBegin() 2.0 1.0 2.0
item.term.Term.toString() 5.0 7.0 7.0
item.term.Term.Term(String) 1.0 1.0 1.0
item.term.Term.Term() 1.0 1.0 1.0
item.term.Term.setCoe(BigInteger) 1.0 1.0 1.0
item.term.Term.merge(Factor) 8.0 9.0 9.0
item.term.Term.getFactorList() 1.0 1.0 1.0
item.term.Term.getCoe() 1.0 1.0 1.0
item.term.Term.extractItem(String) 1.0 13.0 14.0
item.term.Term.equals(Term) 7.0 11.0 11.0
item.term.Term.derivate() 4.0 3.0 4.0
item.poly.Poly.toString() 3.0 7.0 8.0
item.poly.Poly.Poly(String) 1.0 1.0 1.0
item.poly.Poly.Poly(ArrayList) 1.0 1.0 1.0
item.poly.Poly.merge() 4.0 4.0 5.0
item.poly.Poly.getList() 1.0 1.0 1.0
item.poly.Poly.derivate() 1.0 4.0 4.0
item.poly.Poly.createTermList() 1.0 12.0 13.0
item.factor.SinFactor.toString() 3.0 3.0 3.0
item.factor.SinFactor.SinFactor(String) 1.0 11.0 12.0
item.factor.SinFactor.getFa() 1.0 1.0 1.0
item.factor.SinFactor.derivate() 1.0 4.0 4.0
item.factor.SignNum.toString() 1.0 1.0 1.0
item.factor.SignNum.SignNum(String) 1.0 1.0 1.0
item.factor.SignNum.derivate() 1.0 1.0 1.0
item.factor.PowerFactor.toString() 3.0 3.0 3.0
item.factor.PowerFactor.PowerFactor(String) 1.0 2.0 2.0
item.factor.PowerFactor.derivate() 1.0 4.0 4.0
item.factor.Factor.setIndex(BigInteger) 1.0 1.0 1.0
item.factor.Factor.getIndex() 1.0 1.0 1.0
item.factor.Factor.Factor() 1.0 1.0 1.0
item.factor.FactFactory.product(String) 6.0 2.0 6.0
item.factor.ExpFactor.toString() 1.0 2.0 2.0
item.factor.ExpFactor.getPoly() 1.0 1.0 1.0
item.factor.ExpFactor.ExpFactor(String) 1.0 8.0 9.0
item.factor.ExpFactor.derivate() 1.0 3.0 3.0
item.factor.ExpFactor.checkIndex(String) 2.0 1.0 2.0
item.factor.CosFactor.toString() 3.0 3.0 3.0
item.factor.CosFactor.getFa() 1.0 1.0 1.0
item.factor.CosFactor.derivate() 1.0 4.0 4.0
item.factor.CosFactor.CosFactor(String) 1.0 11.0 12.0
error.WrongIndexException.WrongIndexException() 1.0 1.0 1.0
error.WrongFormatException.WrongFormatException() 1.0 1.0 1.0
Total 103.0 177.0 199.0
Average 2.0961538461538463 3.5384615384615383 4.038461538461538

复杂度过高原因分析:

因为此次三角函数因子包含了嵌套因子,在处理这个问题时,此次作业直接为三角函数因子设置了一个表达式成员变量。在进行复合函数求导时,三角函数求导方法就要去调用表达式的求导方法。在这类嵌套调用的过程中会消耗很多的内存资源。
对于整个项目的结构,在与一些同学交流后,发现这次作业的架构大家设计的都差不多,只是在实现的思路有差别。

Bug分析:

自己的bug

虽然对表达式可去除的括号进行了删除,但是对于诸如(x(x(x*(x))))此类的数据,此次作业去除括号降低嵌套深度的方法就不再奏效,在互测中也被屋里的人用此类数据造成了TLE类的错误。

互测时发现的问题:

此次互测不允许提交正确结果为WF的数据,主要提交的样例是针对互测屋内中实现复杂度较高、不对嵌套因子进行处理的代码而构造的。

一点收获

这三次作业中,发现自己设计程序时面向过程的思维过于顽固,在互测期间,我给同学讲述自己的实现时,同学轻易地指出了我哪些地方的写法可拓展性差,后来通过阅读课程组分享的优秀代码,我才开始系统学习例如工厂模式、单例模式等设计模式。
此外,在写完三次OO课下作业后,自己对完成一份优良代码所需要的流程有了自己的认识,加深了自己面向对象的思维,学会去构成类,再将属性、功能抽象出来。

posted @ 2019-03-26 19:49  Hii77  阅读(200)  评论(0编辑  收藏  举报