环球宝贝新一代试管

环球宝贝新一代试管█微★信 号█:138★0226★9370█ ████环球宝贝新一代助孕 █代孕包成功█ ★█代孕包男孩█ ★█

基于度量的三次作业分析

三次作业围绕表达式求导,由一开始的幂函数简单情形,到第二次引入正余弦,再到最后一次的引入复杂的嵌套表达式。这样一个递进的过程,确实体会到了面向对象的核心思想。

我采用的是IDEA的Metric Reloaded插件,以下是用法简介:

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

Dependency Metrics
Cyclic:指和类直接或间接相互依赖的类的数量。这样的相互依赖可能导致代码难以理解和测试。
Dcy和Dcy*:计算了该类直接依赖的类的数量,带*表示包括了间接依赖的类。
Dpt和Dpt*:计算了直接依赖该类的类的数量,带*表示包括了间接依赖的类。

第一次作业

第一次作业输入处理部分使用正则表达式直接处理,每次匹配一个项,之后处理项后面的空格和符号,直到结束。表达式采用hashmap(key是由x和power组成的字符串,对应的元素是该项的系数)处理输入、合并同类项、求导输出。
程序结构方面,主类进行输入处理,然后新建一个FormulaCal类的对象,构建hashmap,并完成求导输出。严格来讲并不是面向对象的设计思路,由于很多功能都写在一起,通过复杂度分析可以看到主要部分的代码复杂度很高。

类图

复杂度分析


依赖度分析

第二次作业

输入处理沿用作业一中的正则表达式,轮流匹配因子的组合以及处理项后面的空格和符号;
表达式处理部分只是将作业一的hashmap的key定义做了简单推广,加人sin和cos的特征,也就是将key重新定义为
"x" + x.power() + "s" + sin.power() + "c" + cos.power()
对应的元素是该项的系数,可以类比作业一种合并同类项的思路,只不过输出的时候需要注意对项内的x,sinx,cosx分别求导。
由于沿用了第一次作业的设计,一些函数同样存在复杂度较高的问题,比如toString函数,以及处理表达式的核心类

类图

扫描二维码关注公众号,回复: 5678444 查看本文章

复杂度分析



依赖度分析

第三次作业

前两次作业"过拟合"很严重,到了第三次不得不全部重写。
第三次作业为表达式、因子、项分别建了类,表达式由项通过加减相连,项由因子通过乘除相连,此外三角函数、幂函数、表达式因子都看成因子的子类,这样每个部分只需要管自己的事情,层次结构也清楚多了。
这次作业的输入处理也用到了正则表达式,因为涉及到表达式嵌套,在匹配项的时候做了一些改动,凡是匹配到出现子表达式的,比如sin( , cos( , (,先去找这个表达式的终结位置的右小括号,之后将左右小括号之间的部分作为一个表达式整体递归处理(不管里面是简单的x,还是复杂的表达式嵌套)。表达式读取完成后,整个树形结构,进行递归求导操作,每个节点获得子节点的导数,处理之后return给父节点,最终完成整个过程。

从复杂度分析可以看到,虽然对结构进行了优化,但是方法个数有点太多了,应该考虑优化,另一方面Term和Expression还是存在复杂度过高的情况。

类图

复杂度分析




依赖度分析

程序bug分析

前两次作业中没有发现bug,可能得益于提交之前的逻辑检查,也就是不依赖于测试用例,直接对程序的逻辑进行分析。不过在程序变复杂之后,这样的检查方式会变得很复杂。

第三次作业暴露出的bug包括两处:

一个是漏掉了对于表达式为0情况下求导的处理,比如sin((x-x))
第二个是由于在化简结果的时候为了减少括号的数量,设定了一些规则判断什么时候需要返回带括号的结果,什么时候不需要,结果漏掉了一些情况,导致了结果的错误。

寻找Bug策略

1.查找一些需求定义边界位置可能会被疏忽的情况,比如任意位置的空格,表达式开头的符号,第三次作业中独有的判定某个因子属于表达式因子还是其他因子。
2.嵌套层数比较多的,比如1+x*(1+x*(1+x*...
3.表面上是带变量的因子但实际上是常数的表达式,比如被强测查出的bug:sin((x-x))

Applying Creational Pattern

前两次作业并没有怎么用到面向对象的思想,结构较为简单。第三次作业进行了改进,使用了继承和接口,设计思路中体现了Factory Pattern的思想。具体来说,一开始为这个表达式构建一个Expression类的对象,每处理一个项就构建一个新的Term对象作为子节点,处理每个项的时候每处理一个因子就构建一个Factor对象加入子节点。构建完成后整体形成一个树状结构,然后调用最顶层的对象的求导函数,这个函数会调用自己子节点的求导函数,这样一直迭代下去,得到最终的结果。
前两次作业可以看成第三次作业的特例,只需要去掉没有被涉及到的Factor的子类,并且调整输入处理使其符合指导书要求即可,对表达式的处理、树的构造方法、递归求导等都可以采用相同的做法。

猜你喜欢

转载自www.cnblogs.com/jiefushengzi/p/10606149.html