其他分享
首页 > 其他分享> > OO第一单元总结

OO第一单元总结

作者:互联网

OO第一单元总结

一、第一次作业

1、类图

优点:结构清晰简单,每个类的规模适中

缺点:Expr、Term、Var类在进行计算时都需要获取HashMap,可以将这个方法抽象到接口Factor中(让Term也实现Factor接口)

2、设计思路

首先在MainClass中读取表达式字符串,利用preProcessing方法进行预处理:处理空白字符、处理**+和*+、处理三+-相连、处理两+-相连、处理带括号的乘方(将乘方变为若干个括号相乘)

将读取的表达式字符串传入词法分析器Lexer,再将Lexer传入解析器Parser,递归下降调用Parser的parseExpr、parseTerm、parseFactor方法,对表达式字符串进行解析

因为解析与计算同步进行,所以当递归下降解析完毕后,返回的expr中的exprVars即为最终结果。在Expr中重写toString方法将exprVars输出即可

3、指标度量分析

(1)总代码规模
(2)类复杂度和方法复杂度

OCavg:类平均圈复杂度,继承类不计入

WMC:类总圈复杂度

ev(G):非抽象方法的基本复杂度,度量一个方法的控制流结构

iv(G):设计复杂度,度量方法控制流与其他方法之间的耦合程度

v(G):圈复杂度,度量每个方法中不同路径执行的数量

其中Expr类中的toString方法的复杂度较高,原因是toString方法中为了输出更短的结果而进行了多次if-else判断特殊情况。Lexer.getVar()和Parser.parseFactor()也存在类似的问题。

二、第二次作业

1、类图

优点:解析、计算、输出三个部分结构清晰

缺点:由于单独设置了一个统一形式的类Unified(最终计算结果可以表示为HashSet<Unified>),该类的方法数量较多;由于Expr没有指数这一属性,所以在Term中添加Factor时,可能需要将某个Expr添加多次

2、设计思路

这次作业在上次作业的基础上增加了自定义函数、三角函数、求和函数,使得表达式字符串的结构复杂度瞬间提高不少,需要对之前的程序进行修改。

3、指标度量分析

(1)总代码规模
(2)类复杂度和方法复杂度

(仅截取标红部分)

由于表达式字符串结构变得更加复杂,导致Lexer、Parser、Customize类的复杂度较高,PrintResult复杂度较高的原因与第一次作业相同。

Lexer.next()中由于curToken具有多种类型,所以与Lexer类中其他方法的耦合度较高。

Parser.parseFactor()中由于Factor的类型较多,所以控制流结构复杂,与Lexer类的耦合度较高,圈复杂度较高,后来也发现这部分的bug较多。这也说明了圈复杂度越高,越容易出现bug。

Customize.getUnifieds()中为了判断参数数量使用了多个if-else语句,因此圈复杂度较高。

三、第三次作业

1、类图

优点:解析、计算、输出三个部分结构清晰

缺点:没有进行含sin、cos的合并同类项

2、设计思路

本次作业与第二次相比,区别在于:sin、cos的括号内不止为常数和幂函数,可以为因子;自定义函数调用时可以嵌套。

3、指标度量分析

(1)总代码规模

可以看到,由于第二次设计架构时考虑到了一些限制条件可能会在第三次作业中取消,第三次作业的代码量并未增加多少,甚至比第二次作业更少。

(2)类复杂度和方法复杂度
image-20220325194107115

(仅截取标红部分)

image-20220325194649807

类复杂度和方法复杂度与第二次作业类似

四、三次作业中出现的bug

1、第一次作业

Expr.toString():代码行数多,圈复杂度高

MainClass.preProcessing():

2、第二次作业

Parser.parseFactor():代码行数多,圈复杂度高

MainClass.main():

CusDefine的构造函数:

Arithmetic.mulUnified():

Arithmetic.mulHashSet():

Parser.findSumExpr():

Customize.getUnifieds():

Sum.cal():

PrintResult.toString():代码行数多,圈复杂度高

3、第三次作业

三次作业bug总结:bug主要出现在代码行数多、圈复杂度高的方法、lexer中pos指向的位置、特殊情况等部分

五、发现别人bug所采用的策略

第一次作业主要关注了预处理、输出以及输出的化简:某位同学预处理无法正确处理---的情况;零一位同学将最终输出字符串中的0+直接去掉,会导致100+20*x+x**2变为1020*x+x**2

第二次作业某位同学的程序无法处理

0
(-+sin(x)**1)**2

第三次作业主要关注了sum函数的上下界可以超出Integer类型,应该设为BigInteger类型

六、架构设计体验

在这次作业中,我第一次接触到递归下降法,由于之前很少用到递归,所以第一次作业做得比较痛苦。对着训练栏目的代码照猫画虎,以为自己差不多写完的时候才发现好像压根没开始计算……(当时以为直接使用toString就行了)赶在ddl前发现了可以使用HashMap进行结果的存储,却因为时间紧迫没来得及深入思考,便将解析和计算糅杂在了一起。(尽管后来发现第一次作业这样设计也还行)

第二次作业在第一次作业的基础上增加了三个新的因子,因此Lexer、Parse等类需要做修改,还需要新增新的类,当时考虑过将三角函数与第一次作业常数、幂函数所在类Var融合在一起变为一个新的类,但考虑到这个类的特性和功能会比较复杂、不清爽,于是还是决定为三角函数新增一个类。后来在第三次作业的设计中也证实了这个做法的合理性。

第二次作业在第一次作业的基础上进行了很大的改动,将解析、计算、输出三个部分分开,新增了一个统一形式的类Unified,将最终结果表示为HashSet<Unified>,并且考虑到了某些限制条件可能会在第三次作业中取消,所以将某些只能为常数、幂函数、因子的地方全部将其当成了表达式Expr类进行处理,很大程度上减少了第三次作业的修改量。

好的架构具有很好的扩展性,能够灵活地添加各种新的功能,因此在写代码前做好设计规划是非常重要的。

在迭代开发的过程中,从第一次作业的直接开写,到第二、三次作业的先设计后编码,我实实在在地体会到了好的设计给编码带来的便利。很多bug可以在设计的时候就发现;有了设计图纸,在编码时思路会更加清晰。

七、心得体会

对Java的语法以及一些非常便利的用法还是不太熟悉,需要加强。在三次作业中,努力地尝试将面向过程思维转换为面向对象思维,目前已经体会到了面向对象构造与设计的一些优点,但对架构的设计还不够熟练,希望能够在后续的课程中不断培养自己的架构设计能力与编程能力。

标签:OO,总结,cos,HashMap,Expr,复杂度,作业,sin,单元
来源: https://www.cnblogs.com/ppr123/p/16057211.html