面向对象第一单元总结-表达式求导

引言

本学期oo的第一单元作业为表达式求导,由于对于java和面向对象较为陌生,第一单元作业总体完成起来较为困难。现对第一单元作业总结如下。

正文

  • ev(G):即Essentail Complexity,用来表示一个方法的结构化程度,范围在[1,v(G)]之间,值越大则程序的结构越“病态”,其计算过程和图的“缩点”有关。
  • iv(G):即Design Complexity,用来表示一个方法和他所调用的其他方法的紧密程度,范围也在[1,v(G)]之间,值越大联系越紧密。
  • v(G):即循环复杂度,可以理解为穷尽程序流程每一条路径所需要的试验次数。
  • OCavg:类的方法的平均循环复杂度。
  • OCmax:类的方法的最大循环复杂度。
  • WNC:类的方法的总循环复杂度。

第一次作业

一、基于度量分析程序结构

1、架构简析

第一次作业的要求较为简单,仅需进行简单多项式导函数的求解,且输入的表达式皆合法。我在这次的作业中构造了三个类,MainClass、Expressionitem。其中MainClass为程序的入口,负责总控和对字符串进行预处理;Expression类负责项的合并与表达式输出;Item类负责项的求导和输出。

2、复杂度分析

本次作业共182行,主要在字符串预处理、生成项和表达式化简三方面方面代码量较大。

1、方法复杂度

image

可以看出几个toString方法以及主类的dealItem方法的复杂度均较高,结构存在不合理之处。

2、类复杂度

image

可以看出Expression类和MainClass类的平均循环复杂度均较高,这是由于将大量处理均集中在这两个类中完成所造成的。

3、类图分析

image

类图如上图所示。

1、设计考虑
  • MainClass类:由于作业所规定的合法格式较为杂乱,所以为了简化处理,在MainClass类中设计了dealString方法对字符串进行预处理,设计了dealItem类进行项的分析和生成。
  • Expression类:把整个表达式看作一个对象。设计的主要目的为进行项的合并和表达式输出。设置了属性itemBox,其为一个HashMap,是盛装项的容器,幂函数的指数作为key值,方便进行同幂项的合并。
  • Item类:把每个项看作一个对象。设计的主要目的在于方便对项做处理。整个架构中最具有面向对象思想的一个类(),其中设计了一系列对项进行处理的方法。
2、优缺点分析
优点
  • 架构简单清晰。
缺点
  • 面向过程与面向对象思想混合。
  • 个别方法复杂度高。
  • 整个架构无可扩展性。

二、自我bug分析

由于此次作业较为简单,在公测和互测中均未发现bug。

三、查找他人bug策略

  • 采用测评机自动生成样例,利用python的sympy库中的diff()函数进行求导,并用collection()函数化简结果,将程序结果与正确结果进行对比,从而进行bug查找。这种方式较为有效,找出了2个bug。
  • 从自己认为的几个易错点出发进行了测试样例的构造,较为有效,找出了2个bug。
  • 由于看不懂他人代码,并未结合被测程序的代码设计结构来设计测试用例。

第二次作业

一、基于度量分析程序结构

1、架构简析

第二次作业为包含简单幂函数和简单正余弦函数的导函数的求解,且输入的表达式皆合法。我在这次的作业中构造了十个类,MainClass、Expre、item、Factor、PowerFactor、SinFactor、CosFactor、Constant、ExpFactor与MultiplyDerivation。本次作业采用括号解析和把表达式因子当作表达式处理的方式进行递归求导,解决了括号嵌套的难点。为了确保正确性和防止栈溢出,仅做了极少量的优化,主要集中在每个类的toString方法。

2、复杂度分析

本次作业共525行,主要在字符串解析、项的构造、求导和标准形式输出四方面代码量较大。

1、方法复杂度

image

image

如上图所示(由于过长仅截出飘红部分)。可以看出解析、求导和输出表达式相关的方法中复杂度较高。

2、类复杂度

image

可以看出,SinFactor、CosFactor、PowerFactor、Item、Expre这几个类复杂度较高,前三者主要是因为加入了一些简单的化简方法,所以分支较多;后两者是因为其中有表达式解析和项构造的方法,所以分支较多。

3、类图分析

image

类图如上图所示。

1、设计考虑
  • MainClass:程序的入口,负责整个项目的总控,并对字符串进行预处理。
  • Expre:表达式类,用来解析、构造表达式,并对表达式求导。
  • Item:项类,用来解析、构造项,并进行项的求导。
  • Factor:所有因子类的父类。
  • SinFactor、CosFactor、PowerFactor、Constant、ExpreFactor:因子类,用来构造因子并进行因子的求导。
  • MultiplyDerivation:乘法求导类,对于两个相乘的因子进行求导并进行简单的化简。
2、优缺点分析
优点
  • 相比于第一次作业,这一次的作业更加面向对象了。
  • 有了一定的可扩展性。
缺点
  • 解析字符串的过程过于复杂。
  • 缺少优化。
  • 构造因子这一复杂过程与Item类耦合在一起,不可复用。

二、自我bug分析

由于为了正确性牺牲了性能,这一次公测和互测依旧无bug。

三、查找他人bug策略

  • 在第一次测评机的基础上改变了生成样例,正确性判定更改为了计算几个随机数的函数值并进行比较,加入了运行时间判断。无效,并未找出bug。
  • 从自己曾经出错的点出发,构造了一系列测试样例,有效,找到了1个bug。
  • 观察他人的代码架构,来构造样例使其输出超过10^4,有效,找到了1个bug。

第三次作业

一、基于度量分析程序结构

1、架构简析

第三次作业为包含简单幂函数和简单正余弦函数及其嵌套组合函数的导函数的求解,并要判断表达式的合法性。这一次的作业仅在第二次作业的基础上增加了一个CreatFactor类,并在各个类中穿插了表达式合法性判断的代码。总体上看,求导部分架构合理,可以确保正确性;而判断合法性部分只是在不断弥补漏洞,无法确定其正确性,并不合理。此外,几乎没有进行任何的优化。

2、复杂度分析

本次作业共660行,主要在字符串解析、项的构造、求导和标准形式输出四方面代码量较大。

1、方法复杂度

image

image

如上图所示(由于过长仅截出飘红部分)。可以看出解析、求导、合法性判断和输出表达式相关的方法中复杂度较高。

2、类复杂度

image
由于相比于第二次作业仅作出微小改动,可以看出类复杂度与第二次作业相似,原因也相同。

3、类图分析

image

类图如上图所示。

1、设计考虑
  • 对比于第二次作业仅作微小修改,处理sin与cos函数嵌套也是将括号内的表达式因子当作表达式递归处理。处理合法性判定仅是在代码各处加入了一些特判和一些化整为零的正则匹配,这主要是因为不会递归下降且想要偷懒()。唯一的改动是将创建因子单独当作一个类进行处理。
  • CreatFactor:用来判断因子的类型并进行因子构建。
2、优缺点分析
优点
  • 将因子构建单独提取出来,增加了代码的复用性。
缺点
  • 判断合法性部分并不可靠,逻辑上也不能完全自洽,以至于最后在强测出现了bug。
  • 缺少优化。

二、自我bug分析

本次在互测中没有出现bug,在强测中出现了一个bug。

  • bug特征:在sin、cos函数中括号内为空的表达式因子,如:sin(()),会被判断为合法字符进行求导,但这其实是非法的。
  • 问题所在的类:MainClass类,在进行最初的合法性判定时,没有将“()”加入非法字符串列表内。
  • 由于仅增加一行代码解决了bug,无法进行对比。

三、查找他人bug策略

  • 采用之前的测评机,更改了测试用例生成方法,很有效,共找出了5个bug。
  • 并未观察他人代码架构进行bug寻找。

重构经历总结

在第二次作业时进行了重构。对比于第一次作业,第二次作业增加了很多类(可见上文的UML类图)和方法。将对应对象所需要的方法都放入了对应的类中,更加面向对象而不是面向过程了;将所需要重复使用的功能抽象成了类,可扩展性也增强了。

经过这次重构使我意识到了事先考虑可能需要的功能的重要性,如果能够事先考虑到后续会有多种因子和嵌套求导,我一定不会构造一个只有三个类、几乎面向过程式的架构。也让我体会到了面向对象对比于面向过程的优越性。

总体而言,重构的目的是因为之前的架构无法满足新的需求,而不是为了优化架构。而且重构的架构仍有许多不足之处,如部分类和方法复杂度过高,没办法进行完备的合法性检查,也几乎没办法在保证正确性和运行时间的情况下进行优化,但是以我目前的能力也只能做到这样了。

心得体会

经过本单元的学习,我真正意义上一只脚跨过了面向对象的门槛,真正有了面向对象的意识,也由java小白进化到了java入门。

总的来说,这三次作业对我来说是一个相当大的考验,毕竟本人什么都学的挺菜。但当真正挺过来之后,也有一种满满的自豪感,“原来我也可以做到”。

从中学到的东西中,最重要的不是写代码的技巧,而是要提前考虑潜在的需求,并为未来留够改动的空间,不然全部推翻重来是非常痛苦的,这就要求必须面向对象而不是面向过程。

最后反思自己的三次作业,其实有很多偷懒的成分在,比如后两次几乎没做优化,比如没有去学习递归下降的方法,所写的代码仅仅是为了完成这个任务,并没有思考过去将其实现的更好、更优雅。希望自己在今后能够有所进步吧!

posted @ 2021-03-28 22:40  禾草  Views(153)  Comments(0Edit  收藏  举报