2021-OO-UNIT1-总结
UNIT 1
一、第一次作业
类图及结构解析
-
MainClass:生成Polynomial实例,将输入的表达式作为target传递给Polynomial类
-
Polynomial:利用正则表达式的处理将输入数据分解为项
- 关于属性)terms:用于存放各项字符串;results:用于存放求导之后的结果
- 关于方法)三个set方法,分别用于求出各项字符串、求导后的结果、结果转化为字符串
-
Term:对于Polynomial类中生成的项字符串,建立对应的Term类,实现解析和求导
- 每一个Term对象都能解析出一个因子的列表,进而用属性存储它的指数和系数。得到求导后的指数和系数
-
优缺点分析
-
结构简单。合理利用ArrayList及HashMap等基础容器。在表达式阶段、项阶段、因子阶段作处理,在复杂度一般的情况下出错率低。
-
扩展性差,导致后续作业的重构。面向对象思想较弱,倒像是在每个类中运用面向过程的思想编写函数。另外,将一些重复使用的代码在多处出现,降低了程序的内聚性。同时,没有考虑到x*x及负项在前等简化情况。
-

类的度量
- 类的属性个数(CSA),方法个数(见类图),平均方法规模(OCavg),类的总代码规模(LOC),带权方法复杂度(WMC)

- 认知复杂度(CogC),方法行数(LOC),方法的控制分支数目(CONTROL),各种复杂度((G))

- 分析:由于第一次作业难度较低,可以看到超出复杂度及代码规模正常范围的类及方法并不多,“红点”具体集中在Polynomial这一类当中。在这一类的求导过程中,采用的方法出现复杂度过高的现象。观察代码可知,复杂度偏高的一部分原因是这一类的求导方法和得出结果的方法存在一定的耦合性,不够内聚。在代码的耦合这一点上,直到后两次作业也没有好好改善,这个问题应该在后续单元中引起重视。
分析程序BUG
- bug:无
发现他人bug方法
-
首先利用Python正则表达式自动生成数据,结合Sympy库可以实现对程序的覆盖性测试
-
在覆盖性测试的基础上,进一步查看他人代码,构造特殊案例(如大数、零值等)
-
在结合他人代码设计测试结构方面,做得还不充分
-
最终找到两位互测屋同学的bug
二、第二次作业
类图及结构解析
-
MainClass:将输入的字符串传递给工厂,打印工厂生成的结果
-
Thing:基本接口,本项目的表达式、项、三元组均实现了该接口。Thing最重要的方法:derive(),表达式、项、三元组均需实现对于该方法以及其他打印结果等方法的重写。
-
Factory:用正则表达式解析传递给它的字符串,判断该字符串对应的是表达式、项还是三元组因子。根据这一点,生成对应的类的实例。
-
Cell:三元组(sin,cos,x),是架构的最基本单位。每个实现了Thing接口的类均管理了Cell-系数的HashMap。
-
Poly和Term:表达式及项。表达式求导时各项求导结果相加。项求导时各项结果根据乘法求导原则作运算。
-
优缺点分析
-
面向对象思想较上次作业有所提升:不在整体过程上考虑,而是对于每一层次的对象(从表达式到项到因子),提出其求导时遵循的逻辑。在每一对象中做好求导,整个项目的架构自然实现。同时,通过维护每一层次对象的三元组HashMap,确保了正确性和最终结果的性能分。
-
扩展性差,导致后续作业的重构。程序耦合程度极高,例如项和表达式两类中均有重复出现的操作(如合并HashMap)。整体思路不够清晰,如在Cell(三元组)对象中仍然维护一个永远只有一元的Cell的HashMap,造成写码时的混乱不堪。
-

类的度量
- 类的属性个数(CSA),方法个数(见类图),平均方法规模(OCavg),类的总代码规模(LOC),带权方法复杂度(WMC)

- 认知复杂度(CogC),方法行数(LOC),方法的控制分支数目(CONTROL),各种复杂度((G))


- 分析:整体而言,代码规模均控制得较好。由于Poly类和Term类存在大量耦合且冗长的代码,本来以为二者的复杂度均会较高。但是出乎意料的是,Poly类在方法的平均复杂度以及各个方法复杂度上均表现尚好,而Term类则不出所料地呈现高复杂度。再回顾一下当时的代码也不难理解,为了时时刻刻控制和维护三元组,在Term中对于乘法求导作了很繁琐的操作,也没有将操作的主体视作一个对象以用面向对象的思想解决。这提醒了我,面向对象的思想还要在写码中逐渐培养。同时,Factory类的整体复杂度也很高。这应该是因为在这一类的product()方法中,同样用面向过程的思想,企图在一个方法中从头识别到尾。值得吸取教训。另外,在代码的耦合程度上,本次架构的耦合性较第一次作业有过之而无不及,具体集中在Poly和Term两类中。这一定程度上导致了第三次作业的重构。
分析程序BUG
- bug:无
发现他人bug方法
-
首先利用Python正则表达式自动生成数据,结合Sympy库可以实现对程序的覆盖性测试
-
在覆盖性测试的基础上,进一步查看他人代码,构造特殊案例(如大数、零值、多个括号嵌套等)
-
在结合他人代码设计测试结构方面,较上次有所加强。例如,针对某同学的化简代码,有针对性的设计数据,发现了其在化简过程中的错误
-
本周同样找到两位互测屋同学的bug
三、第三次作业
类图及结构解析
-
MainClass:创建FormatCheck对象 -> 通过创建Factory对象进而求导 -> 创建Symplify对象实现化简
-
FormatCheck:通过正则表达式等方法检查输入字符串的空格、指数大小、整体结构是否正确
-
Thing:基本接口,本项目的表达式、项、sin、cos、x、常数、函数嵌套均实现了该接口。Thing最重要的方法:derive(),每个实现了该接口的类均需实现对于该方法进行重写,从而得到求导结果。
-
Factory:用正则表达式解析传递给它的字符串,判断该字符串对应的是哪一个实现Thing接口的类。根据这一点,生成对应的类的实例。
-
Nest:函数嵌套。它的derive()方法将利用函数嵌套的求导规则得出求导结果。
-
Poly和Term:表达式及项。表达式求导时各项求导结果相加。项求导时各项结果根据乘法求导原则作运算。
-
Power、Sin、Cos、Constant:基础因子。不同于第二次的三元组,将基础因子作为求导的基本对象,得到求导后的字符串。
-
Symplify:简化表达式。在每一项中实现简单的合并同类项操作,使求导结果有效缩短
-
优缺点分析
-
观察类图可知,本次项目架构的层次化较前两次作业更清晰,更井然,更有序。(前两次作业的类图均呈现自上而下长方形的状态,水平维度未呈现较清晰的结构。这次类图的结构层次则一目了然,自上而下,自左而右,呈现清楚的对象逻辑)
-
因为本次作业的复杂度提高(函数嵌套等的引入),无法如上一次作业简单地用三元组表示每一项。故在求导过程中,用字符串作为了每一类中的关键属性(而非管理一个三元组的HashMap)。这样操作使正确性较难保证,使求导过程中思维更混乱,间接导致了bug的诞生。
-

类的度量
- 类的属性个数(CSA),方法个数(见类图),平均方法规模(OCavg),类的总代码规模(LOC),带权方法复杂度(WMC)

- 认知复杂度(CogC),方法行数(LOC),方法的控制分支数目(CONTROL),各种复杂度((G))



- 分析:代码总行数达到800以上,代码规模控制得不好,一定程度上是由于耦合程度过大导致。在FormatCheck,Factory,Symplify类中均有类似的通过正则表达式对字符串进行处理的方法代码,程序内聚性差。在类的复杂度上,三个具有明显功能性的类:FormatCheck,Factory,Symplify的复杂度超出正常范围,说明了本人还不能很好地用面向对象的思想编写功能类,依然按照面向过程思想处理表达式求导问题。而各个层次单位:如表达式、项、因子的复杂度均控制得较好,这一点和第二次作业比有所进步(第二次作业的Term类的各个方法复杂度明显偏高)。
分析程序BUG
- bug:简化较复杂表达式时会超时,同时生成BigInteger时采用了先生成Long类型再将Long转换为BigInteger的方法,导致了强测被Hack2点,弱测被Hack一次。bug出现在FormatCheck和Factory两类当中。
- 个人认为,本次bug的出现与代码复杂度并不直接相关。但是由于在编写功能类时代码耦合程度过大,提高了复杂度,导致编写代码时的逻辑思维混乱,从而间接地导致了出现bug的失误。
发现他人bug方法
- 本周通过观察他人的代码,结合互测屋中某位同学关于格式检查的结构,设计出了令其错判格式问题的输入(即所谓的假阳性)。
四、重构经历总结
- 本单元三次作业,重构三次,每次的作业都是全新的开始。各次作业的类图及度量度分析均已在上面展示。注意到,这三次作业在复杂程度上呈现一个较稳定的状态,这个稳定指的是都具备一定的复杂度但又不算过于差,整体来说并没有明显的上升或是下降趋势。这也说明了,在本单元作业中并没有很好地提高自己的工程设计思想和面向对象的代码设计能力。也正是因为这个原因,才导致次次重构吧。另外,观察每次重构的代码对比可发现,每次作业的架构均存在明显不同,可以说完全不一样,也就是说我只是对于一个问题简单地分析并设计架构,并没有考虑架构的扩展性和合理性。在下一单元作业中,应该注意的是:在做每次作业时了解下次的扩展需求,让自己的架构保持可扩展的灵活性。吸取教训,以迭代开发替代一味重构。
心得体会
-
一个心得体会是,OO作业确实在提高我编写程序的能力。这不仅仅体现在每次实现表达式求导的基本功能的经历上,也体现在编写自动测评机时对每个需要用到的参数的查阅上,体现在每次debug时bug定位的艰苦历程上,体现在为了取得更高代码风格分而无形中增长的代码规范意识上。在互测的过程中,我也在别人的架构中收获良多。
-
另一个心得体会是,OO正在对我进行很好的心理素质培养。作为一个编程能力较弱的人,每次作业的开始,都处在一种非常茫然、觉得自己这周实在没有办法完成作业的状态。在这种状态下逼迫自己去一步步实现架构,最后竟也能回过头来说“这也不算什么”。bug的出现更是对我进行挫折教育,从互测到强侧不断鞭尸,最开始为自己的程序存在自己不知的bug而心情极差,后来也调整过来心平气和地修复bug。
-
总而言之,第一单元的体验尚好,收获颇丰,从各种意义上来说,都感谢辛勤付出的课程组老师、助教,感谢帮助我的学长、大佬。

浙公网安备 33010602011771号