一、程式結構分析 第一次作業 1.設計構思與自我評價 第一次作業難度不是太高,只需要解析由常數、冪函數簡單組合的表達式。其中每一項都可以看做coef*x**index的固定形式,建立包含coef,index兩個Biginteger屬性的Term類作為最基本的數據結構,並且實現單項求導的方法。在Ter ...
一、程序结构分析
第一次作业
1.设计构思与自我评价
第一次作业难度不是太高,只需要解析由常数、幂函数简单组合的表达式。其中每一项都可以看做coef*x**index的固定形式,建立包含coef,index两个Biginteger属性的Term类作为最基本的数据结构,并且实现单项求导的方法。在TermList中实现读入表达式后的构建、整体求导与化简。
由于题目中表明空白字符对格式判断的无影响,在读入表达式时就可以将所有空白字符去除,简化拆分表达式的操作。解析表达式时我首先尝试了有限状态机的方法,按字符读入。然而这一方法在后续作业中由于过于复杂,状态太多而容易出错,被其他方法所取代。简化时只需要比较两项的系数是否相同即可。
这次作业由于没有考虑后续功能增添以及更加复杂的解析处理,采取了不太恰当的处理方式,扩展性不够强,后续的作业中重构花费了较多的时间。并且对与面向对象思想的体现还不够。
2.度量工具分析
UML类图:
复杂度与耦合度
由于主要功能都在TermList中实现,造成TermList类的复杂度和耦合度都比较高。
第二次作业
1.设计构思与自我评价
这次作业相比上次变化不是太大,增添了对三角函数sin(x),cos(x)的要求。因此每项Term都可以看成是coef * x ** xindex * sin(x) ** sindex * cos(x) ** cindex的格式,每一项需要四个参数,我在这里将每一个因子都包装为一个单独类,采取组合的方式实现Term的结构。其余结构基本上延续了上一个作业的做法。
同样的,由于空白字符不造成影响,在读入表达式时将所有空白字符去除。解析表达式这一步有了较大的差别,考虑到复杂程度的显著增长,我放弃了有限状态机的解析方式,而是采取正则表达式的方法。通过构造大正则表达式的方式匹配整个式子是否符合format(大正则表达式由诸多小正则按层次相加构成,保证可阅读性,可复用性)。小正则用于从表达式中将每一项每一个因子提取出来,以实例化Term加入TermList。
求导的思路与上次作业基本一致,整体的求导转化为每一项求导的和,用ArrayList或HashMap储存,按照公式即可。简化时首先比较两项的三种指数是否相同,再考虑sin(x) ** 2 + cos(x) ** 2 = 1,以及x ** 2 = x * x等情况,遍历合并后输出。
2.度量工具分析
UML类图
复杂度与耦合度
由于采取了较上次作业更加面向对象的方式,这次的复杂度和耦合度较上次有所改善。但是由于主要功能并没有单独封装,而是整合在Term或TermList类中,仍然有改善的空间。
第三次作业
1.设计构思与自我评价
这次作业难度有了较大的提升,括号嵌套的加入带来了迭代的问题,意味着之前的解析、求导方式都不再适用了,需要较大的改动。但也有一部分可以复用。由于写代码前时间不够充分,思考不够充分,面向对象思想的设计没能很好的体现。最终选择了表达式二叉树的方式来建立数据结构。在这次作业中,我将表达式细化为因子之间的二元运算,表达式树的每一个节点都是一种运算或是因子(叶子节点),三角函数的嵌套也看作是一种运算。
解析表达式时,细分为因子和运算两种元素的组合,避免了大正则的出现,仅用来提去出不同因子。利用栈的思想,定义每一种运算的优先度,构造出表达式二叉树。由于检查格式和二叉树较难结合,我将检查格式的操作单独整合为一个类,在构造数之前就进行检查。
此次化简主要是简化不必要的运算,比如0,1的乘、幂运算,0的加减等,并且对三代之间的常数运算加以合并,避免出现常数相乘直接输出的情况。
表达式树的建立对于复杂运算的解析有较好的适应性,思路清晰,有一定的复用性。缺陷主要在于格式检查逻辑有些混乱,没有和树结构很好的联系起来,另外由于时间不足,输出结果的化简上还有较大的优化空间。
2.度量工具分析
UML类图
复杂度与耦合度
由于这次作业难度的增大,情况多变,操作更加复杂,我也没有很好的实现层次性,少数类中实现了过多的方法,造成复杂度和耦合度都不太理想。敲代码前应当更好的去构思我的设计。
二、关于Bugs
Bug分析
前两次作业中自己的Bug主要出现在WF的判断,特殊情况没有考虑到,其实都是很容易避免的。第三次作业还出现了越界的情况。复杂度提高的情况下,对细节的把握不太到位,还是没有耐心做到充分的测试,周全地考虑问题,造成了不少bug的出现。
测试
互测中我发现的bug并不太多,一部分原因在于没有搭建出良好的评测程序,造成测试效率不高,但还是总结出以下常用的测试思路。
a.无脑使用数据生成器,生成覆盖功能较广的数据,进行黑盒测试,以快速找到bug。
b.结合自己完成作业时的情况,尝试容易犯下的错误和边界值。
c.阅读对方代码,从代码逻辑上找出错误。
三、对比与心得体会
初来乍到,从面向过程转到面向对象还有些不适应的地方,很多思路需要转变。之前就听说OO的恐怖,现在也算是深有体会了。但是遇到的挑战越大,战胜挑战的收获也越多。
三次Homework的难度逐渐增大,不断地查阅新的java语法,学习新的容器的使用方法,了解Factory等设计模式,让我慢慢地向面向对象的正轨上转变。通过各种渠道看到大佬们的设计,只能觉得自愧不如,自己的代码比起来还是太幼稚了。无论是架构还是优化,还是bug率,我都还有很大的进步空间,需要学习的还有很多。在今后的作业中,我会更加注重面向对象的思维方式,在架构设计方面投入更多的精力,做到良好的可扩展性、真正意义上的高内聚低耦合。