- 设计思路
- homework1
- homework2
- homework3
- 程序度量
- 结构分析
- 代码行数分析
- 复杂度分析
- Bug
- 应用对象创建模式
- 心得体会
设计思路
第一单元作业的主要任务为函数的求导,从作业1到作业3难度依次增加。作业1的任务为简单多项式的求导,给出了多项式的形式化表述,并且不要求进行格式检查;作业2新增加了项和因子的概念,一个表达式由多个项相加,一个项由多个因子相乘,而每个因子可以是幂函数、正余弦函数或者常数,并且要求格式检查;作业3进一步针对三角函数增加了复合函数求导的要求,三角函数内部可以复合表达式。
homework1
因为表达式为简单多项式,我们只需要用 ArrayList 等可变长的结构去存储每一项的信息即可。每一项都是一个幂函数(常数也可以看成幂函数),需要记录系数和指数,在项这个类中实现求导、toString 等方法,然后表达式类的实现实际上就是各个项的累加。
对于输入数据的提取,我们可以利用形式化表述构建正则表达式,按项拆分后提取信息即可。
考虑优化输出长度,我们可以用 HashMap 来记录项的信息,key 为幂函数指数,value 为幂函数系数,这样可以很方便地进行合并同类项的操作。
homework2
同样地,表达式是由多个项相加而成,而且每个项都有固定的因子乘积:(coe)*(x**powX)*(sin**powSin)*(cos**powCos)
,所以大体的结构在 homework1 的基础上可以不用修改多少,我们主要修改项这个类的内容就可以了(另外这里项的求导会得到一个表达式类,要增添表达式合并的操作)。
homework3
第三次作业增加了复合操作,可以看出原来的结构处理不了这种情况,所以只好重构。我构建了一个 factor
接口,接口要求实现求导和 toString 方法,然后建立了Sin
, Cos
, Power
, Multis
, Adds
五个类,分别记录正弦、余弦、幂函数、多项乘积、多项和的信息(工厂模式)。 Sin 和 Cos 记录了 sin/cos(fac)**pow
这样的信息,其中 fac 是一个 factor 类,pow 是指数;Power 记录了指数信息(本次作业不要求幂函数的复合);Multis 和 Adds 分别实现了一个 factor 的 ArrayList。这样的话,表达式实际上就是一个 Adds 类。通过对每个类实现求导和 toString 方法,就可以很好地完成任务。
由于复合导致不能仅仅用正则表达式处理输入信息(因子和表达式相互嵌套),我们可以考虑对输入进行递归处理。我的处理方法是:在处理当前表达式时,用栈将所有最外层括号找出来,然后把这对括号包括里面的内容替换为一个 subStr(比如说"#"),然后将里面内容保存;预处理完之后,对形式化表述稍作修改,我们就可以利用正则表达式提取信息(因为预处理之后不再有嵌套);在提取信息时,每遇到一个 subStr,就拿一个刚才存储的内容出来,对这个内容(其实也是一个表达式)递归表达式处理,处理结果合并到当前表达式处理之中。
在这种思路下作业3有很多细节问题,需要多多调试。
程序度量
仅针对作业3,进行结构分析、代码行数分析和复杂度分析。
结构分析
作业3的程序结构(UML图):
代码行数分析
作业3代码行数(LOC):
可以看到总共行数为593行。
复杂度分析
作业3类复杂度分析:
其中 OCavg(Average operation complexity) 表示每个类的非抽象方法的平均循环复杂度,WMC(Weighted method complexity) 表示每个类各个方法的总循环复杂度。
Bug
第一次作业:处理时一边迭代一边删除元素导致了ConcurrentModificationException
异常。
第二次作业:未发现。
第三次作业:
- 输出时出现了
x*+(...)
这样的错误(表达式因子前面没有正负号); - 输出时出现了
()
这样的错误(空括号);
可以看出,第三次作业主要的bug都集中在最后的输出上面,根据我的分析,因为我们要执行 toString 时,对于各个类还要考虑其他类的输出结果(因为很多类的属性中都会嵌套 factor ),所以很多细节问题需要多多debug。
找别人的bug主要就是用的自己的自动化测试啦。
应用对象创建模式
从设计思路部分可以体现。
心得体会
通过本单元的学习,我大致掌握了java这种OO语言的基本使用方法,并且熟练掌握了工厂模式、正则表达式、接口、继承等等知识。
在自动化测试方面,我的自动化测试还有很大的不足之处,具体表现为:
- 数据生成几乎是随机性的数据,没有针对性和覆盖性;
- 没有考虑到 sympy 可以正常识别
x*+(...)
这种实际错误的格式,导致没能检查出作业3的这个bug(强测错的4个点全是这个问题),经过思考,其实可以把输出结果再用java代码判断一次格式是否正确; - 自动化测试过程中,只有WA才会报错(也就是python标准输出计算结果与java输出计算结果不一致时),而java编译运行过程中的异常不会导致评测机报错退出,所以作业1的异常bug和作业3的
()
bug(实际上python读取时会有异常)没能检查出来。
之后还是要好好改进自己的评测机。