OO第一阶段总结
To Start With
oo之旅有苦有乐,三次作业一次比一次难。不过每解决一个bug,似乎都感觉自己变强了一点呢?(苦笑;
接下来是我对这三次作业的总结。大致包括了我对自己每次程序结构的分析、对自己所出bug的反思和对测试其他同学代码时所用到的小手段。
让我们一起来看看吧
第一次作业分析
类图(由AmaterasUML自动生成)

Q:是不是看起来特别奇怪?那些本来该有的箭头都消失去了何方?
A:这就是第一次写java程序获得的教训。
在第一次作业里,我把所有的class都写在了一个文件里。虽然写的作业是面向对象的课后作业,然而写法却是完完全全的面向过程。
Metrics 度量分析(使用idea的MetricsReloaded)
Method mertrics
ev(G)用来衡量程序的非结构化程度。ev(G)栏的数字变红(值越大)说明代码非结构成分多,增大了代码维护的难度,使程序难以理解。由于非结构化程度高,在debug时可能会出现补东墙时不小心把西墙给拆了的情况——即在debug时引入新的Bug。因此ev(G)越低越好。
iv(G)用来衡量模块判定结构,即模块和其他模块的调用关系。软件模块设计复杂度高意味模块耦合度高,这将导致模块难于隔离、维护和复用。
v(G)是用来衡量一个模块判定结构的复杂程度,数量上表现为独立路径的条数,即合理的预防错误所需测试的最少路径条数。
我们一眼就可以发现,oo_1.Calculation.Calculation(String)和oo_1.Calculation.printOut()的ev(G)被标为红色。
我在oo_1.Calculation类的构造方法Calculaiton(String)进行了多项式的计算。具体包括将每个多项式的(c,n)以及多项式前的+/-号提取出来,然后进行累加(减)。现在看来,在构造方法里进行计算不仅代码逻辑较为复杂,而且有些难以理解。如果要修改的话,我会在构造方法里仅仅进行存入这个String值的操作,然后将计算剥离至新建的方法中。oo_1.Calculaiton.printOut()执行打印相应结果的操作,之所以被标红,个人觉得不是因为复杂度高,而是由于if/else分支嵌套较多,导致代码逻辑显得复杂,实际上用人的思维去理解会发现并不复杂(Lol)。
Bug分析
我第一次作业出现bug的原因主要在于个人过于自信,测试不足。由于在计算的时候没有进行try-catch操作,导致出现了ArithmeticException!!!针对这一点,我于接下来的两次作业中都在main方法中直接进行了try-catch操作,try住main方法里所有的内容,保证了程序不会出现crash的情况。
第二次作业分析
类图(由code iris自动生成)

可以看出,第二次作业相比于第一次,类图丰富了许多。类之间不同的箭头代表了他们之间的关联关系。(具体可以参考 https://blog.csdn.net/liujian20150808/article/details/51099072)
Floor类在本次实验中作用很小,仅仅存储了楼层指令的到达时间。Reader类则是进行读入,在main方法中实例化各个类,然后逻辑运行,得到结果。Request类负责接收Reader里读入的每一行字符串,随后进行正则表达式的匹配,如果匹配失败,则打印相关信息,匹配成功的话就加入到RequestArray类的请求队列里。电梯的相关运动状态由Elevator类负责存储和执行更新,由Scheduler类调度电梯的全局运动以及相应的信息更新(时间等)。
Metrics 度量分析(使用idea的MetricsReloaded)
Method mertrics

oo_2.Reader.main(String[])的ev(G)被标为红色,个人觉得是因为在代码里使用了while(true)来读入电梯指令(存疑); oo_2.RequestArray.addRequest(Request)的iv(G)和(G)都被标为了红色。这个方法的功能是将传进来的Request对象进行再次判断,符合要求的存进请求队列里。现在来看,我对于判断请求是否正确而做的工作明显繁冗,因为我在两个方法里进行了两次判断,只有符合这两次判断的才能被成功添加进请求队列。我将这一个功能分裂在了两个方法里,而实际上放在一个方法里,会使代码耦合性更低,更利于维护。oo_2.Scheduler.schedule()方法标红,我想是因为我将Scheduler类的所有功能集中在了这一个方法里,即这个方法完成了判断同质、调度电梯运动等功能。这个方法所包含的功能太杂,不单一。不利于修改和继承,导致我第三次作业直接完全重写了这个方法。
BUG分析
这次作业的难点主要在于Scheduler类的调度,判断同质请求需要注意是否计算开关门时间。
第三次作业分析
类图(由code iris自动生成)

这次的类图相较第二次实验更为复杂。NewScheduler类继承了Scheduler类并且重写了schedule()方法。Er定义了Elevator类的一些接口。其余逻辑大致上和第二次实验相同,不多赘述。
Metrics 度量分析(使用idea的MetricsReloaded)
Method mertrics


虽然说看起来ALS电梯只是增加了捎带功能,实际上代码的复杂度较之上次大了不少(也可能是我把问题想复杂了?)oo_3.NewScheduler.same(Request)用于判断Requset类的请求是否同质。我这个方法的ev(G)标红,应该是因为if/else分支过多导致。oo_3.NewScheduler.shedule()和oo_3.NewScheduler.take()方法三路全崩,损失惨重。这两个方法首先代码极长,其次if/else分支多,进行的功能杂。take()方法在判断能否捎带之余还负责更新了下电梯被捎带指令时间,这个功能不应在此"顺带完成"。而且由于这个顺带操作,我在debug时引入了新的bug,以至于一时半会儿都找不到彻底解决bug的方法。schedule()的代码量长的一大原因是出现了极多的if/else,而每个分支内代码内容又相似,以至于出现了极多的复制粘贴。代码量太长,这导致我在debug时出现了许多困难。其余标红的地方和第二次实验的原因相同(因为功能几乎一样就直接把上次的复制了过来,做了一点点修改而已)。
BUG分析
我在最终公测后发现自己程序居然catch住了一个Exception。我在本地测试后,发现了是NullPointerException。这给我提了个醒,在if/else分支下,最好别写else,只要能知道else时的条件,就用else if写全判断条件。因为可能出现判断条件未赋初值(仍处于Null状态)却进入了else分支而导致程序crash的情况。
测试的小小手段
在互测阶段给别人debug时,有一些小小的技巧(当然了这个技巧也是要基于别人代码有Bug才行,毕竟Bug总不能无中生有吧)。
1、详细阅读被测者的ReadMe
在第二次实验中,我de出了被测者3个bug。而其中有一个bug得来毫不费吹灰之力!被测者在ReadMe中对输入格式的定义和指导书发生了冲突,然而公测点却没有检测这种情况。在认真阅读完他的ReadMe后,我随机构造样例进行测试,发现了这一bug。
2、分析被测者代码逻辑,测试可能出现错误的边界情况
阅读别人的代码是一件相当艰难而痛苦的事情!但是为了有所依据地测试他人代码,而非凭空创造测试集,我们需要对源代码进行阅读。即使无法完全领悟其中精髓,但在粗略阅读过后,应该能大致明白每个模块的功能,然后再思考如何构造测试样例
3、压力测试
有些样例之所以无法找到被测者的BUG,很可能是因为测试数据太短,命令太少,没有触发产生BUG的条件。在压力测试下,面对数百条指令,一些细微的bug也能被发现哦(对自己的代码进行测试同样十分有效!)。
心得体会
饮了三周Java之茶,我只感觉我的寿命在随着时间指数般流逝~
稍微说的有点过,但是如果不尽早开始写,很有可能因为de不完bug而通宵坐在电脑前苦苦挠头啊。
看了自己代码的度量分析后,仔细回顾了这三次作业,对每一次都不怎么满意。不是因为代码有bug而内心失望,只是感觉自己对oo还是一片懵懂。什么样的代码鲁棒性才强,如何让自己的代码做到高内聚低耦合?为什么我总是在一个方法中情不自禁地实现多个功能?我只感觉到:Long Way to Go.后面还有很多次在oo的课后海洋里被水淹没,不知所措的机会。希望自己能够坚持下去,不放弃,就算熬夜通宵也解决掉每次作业吧!


浙公网安备 33010602011771号