第一单元的面向对象编程作业已经全部落下帷幕,终于能有个时间空闲来分析一下自己的编程作业了。
首先,三次作业的框架如下
图1.第一次作业框架
图2.第二次作业框架
图3.第三次作业框架
一、基于程序结构的分析
1.对类型的分析(关键词:实类、虚类 PS:自创名词,意指真实存在的类和过程的抽象的类)
通过这次作业,我对面向对象的思想又多了许多理解。
第一二次作业类的命名,诸如ParaString, DeriList,PrintQueue等,我基本上采用的是虚类的命名。虽然是名词,但总是有一种奇怪的感觉。现在仔细想想,命名的对象实在太近于过程。例如DeriList,我最初对这个类赋予的定义为“求导序列”——加入这个类主成员为Arraylist,内部为一系列的系数和幂值;类的方法为deri()即求导方法,即:
1 public class DeriList { 2 3 public DeriList(Arraylist a) { der = a }; 4 5 private Arraylist der; 6 7 public deri() { 8 ... 9 } 10 }
后来眉头一皱,一想只有一个成员一个方法,干脆就将成员删去,直接向方法内赋予参数。然而写完就发现了,DeriList的类简直累赘,里边有用的仅有一个方法,这个直接使用方法就行了。使用类,首先得在主类中建立对象,通过引用对其操作,而类中仅有一个方法,也就是说我如果把这个方法放进其他类中,也就省去建立对象等操作了。从头理一遍,如果我 类例如Poly,将方法放入其中,是更好的选择。建立了一个DeriList的类的目的仅是为类的存在而建立类,本末倒置。
因此在第三次的作业中,我使用了Analyser和ThirdFunc两个实类,不仅看起来这两个类也更对象,就连摸起来内部定义的变量和方法也更对象了。
Analyser:
1 public class Analyser() { 2 public Analyser() { } 3 4 public int inputCheck() { 5 ... 6 } 7 }
inputCheck自然而然属于Analyser的功能之一,这样不仅提高了程序的可读性,更贯彻了面向对象的思想。
2.基于度量的反思与评价
本单元作业内类的属性个数、方法个数、方法规模等度量方面,我安排的都不好,总是一两个,类显得空荡荡的,不太值得为方法和成员开类,因此类的成员和方法控制在4个左右。方法规模不超过60行,以30-40行最佳,方便阅读。
前两次作业我基本按照面向过程的思想来写的,流水线工作,除了主类集合其他类,其他类之间没有耦合关系,只是次序关系;每个类里只有一个方法,无内聚关系。第三次作业使用了Analyser(格式分析)和ThirdFunc(第三次格式方程):Analyser只有check方法,ThirdFunc里有deriFac,deriTer,deriExp,三个为循环关系,如下图所示:
图4.ThirdFunc方法内聚关系
类之间的划分比较明确,无繁杂的耦合关系。
二、基于BUG的分析
序号 | 样例 | 输出情况 | 正确输出 | 错误原因 |
01 | x-x | 0 | 优化过程中把项为0的删去,未考虑仅有0的情况 | |
03 | x*-1 | 异常 | -1 | 分离项时未考虑负数因子 |
几乎所有问题都是出现在优化设计上面,未考虑特殊情况,与结构无关。
三、互测数据的构造
分析bug时基本没有把完整的代码看完,我采用的策略是仅分析格式判断和输出优化上面。将所有的代码固然可以完整的掌握(前提看懂)程序的运行过程,有利于分析出bug,但这却是一项很耗时的工作,效率不高。debug的过程就好比拿矛刺盾,对一张盾牌的各个位置刺一枪会发现盾的弱点,但更多的是miss,近乎无用的工作。但将更多的刺探放在盾的衔接处,无疑会大大提升破盾的可能性。
分析这三次的作业,可分为三个主要过程——格式判断、求导计算和优化输出。首先,在格式判断上面容易出现bug。阅读题目的时候,我们可能不会面面俱到,考虑到所有情况,并且这部分的判断基本利用正则,因此我认为分析格式判断的代码是可取的策略之一。在求导计算的过程中,大多计算不难,有固定的格式,基本上经过中测就几乎没有什么错误。我在优化输出过程中出现较多的bug,都是因为没有考虑到优化后的结果导致输出格式错误。因此在优化的过程中也容易出现bug。
综上,在构造样例时,我会针对格式和优化的代码,构造出随机样例测试。
四、面向对象的思想重构作业
第一二次的类的可根据第三次的作业框架重构,除了主类外,构造分析器类和多项式类。