在正式写oo做业以前,先说一些“废话”吧,就当是对oo的吐槽。java
事实上,早在大一的时候,据说数分很难,然而事实证实数分并无有让我通宵的体验。正则表达式
在大二上的时候有一门课叫祭祖,号称是第一门给咱们“推背感”的课。可是我也是很好的摸了过去,从P5才开始通宵。(虽然本菜鸡只是止步于P6而已)编程
早有耳闻北航的oo是一门很是“坑”的课程,开始我还不觉得然。然而当第一周基本啥都没讲就给咱们留了一个多项式相加的做业时,我才意识到事情并无那么简单。数组
到第三周的ALS电梯已是须要熬到1点钟,我一边血泪控诉oo(骂着我这个版本的eclipse很差用,控诉这门课的难度(心态崩了) )一边写代码debug。直到DDL前一天才解决了全部的bug,设计总算有了眉目。才仅仅通过三周,感受像经历了什么大的挫折同样。(多是由于我太菜了)框架
那么接下来我再来针对具体的三次做业来写写本菜鸡是如何在三次做业中survive下来的。eclipse
事先声明的是,在此以前我没有学习过面向对象的课程,包括暑期的面向对象先导课我也没有参加。(据说暑期的先导课效果很好,若是当时学习了估计此次做业不是很成问题)函数
甚至我连JAVA都没有学过,还好在寒假的时候听了同窗的建议,在网上找了JAVA的学习视频学习了一段时间。至于学习效果如何,固然是不太好的。由于只是看视频,没有动手写代码,没有通过系统的训练。这样学习一门语言,每每只是掌握了基本的语法而已。对语言的运用则很成问题。虽然掌握的很差,可是不至于没法入门,总比零基础来编写要好。工具
由于对JAVA面向对象思想理解的不深,致使最后差点写成了个和C差很少,面向过程的代码。好在第一次做业比较和蔼之处,是PPT上给出了一个大致的框架。根据这个框架来补充代码,基本上算是勉强实现了面向对象。学习
这里附上度量分析和类图测试
能够看出来飘红的点是圈复杂度,方法则是parsePoly,即将字符串分析出多项式的方法。这个方法圈复杂度高的缘由恐怕是由于没有使用方便的工具matcher和parseInt来读取数字,而是使用了很麻烦的方法(即C语言的方法)来读取,致使这个方法须要的工做太多。
设计思路上彻底与PPT上的框架一致,所以不在此赘述。总的来讲,之前没有接触过面向对象,第一次做业能按照PPT的指导来写面向对象,可能算是一个优势吧。
(1)一开始在编写的时候,根据前辈的慕课教导,使用了正则表达式这一强大而可靠的工具,这点仍是值得庆幸的。若是没有了解到这个工具,按照状态机来判断格式,洋洋洒洒能写出庞大的代码量。可是那样的代码,不管从可读性,可靠性,都不如利用正则表达式来的实在。并且用状态机来写,不免会出现考虑不周的状况,从而让人抓住马脚。
(2)早在寒假时就接触到了一句格言“不要重复造轮子”(Stop Trying to Reinvent the Wheel)可能辛辛苦苦码出来一堆东西,最后发现早有现成的工具让我来用了。好比此次做业中,读取数字这一部分,我采用了以下代码
if(buf[i] == '-') negative = -1; else { for(current=0;buf[i]>='0'&&buf[i]<='9';i++) { current = current*10+buf[i]-'0'; } } if(buf[i] == ',') { coeff = current * negative; negative = 1; }
用negative判断负号,用for循环读取数字,活脱脱的一个C语言读取数字的典范。(事实上我是先写的C程序,这段基本就是从C代码复制过来的)这样写,虽然没有问题,可是,一个字,蠢。在拿到第二份做业指导书的时候,要读取数字,我这时候才发觉用状态机判断的麻烦,开始另辟出路(面向百度),知道了用matcher来把字符串转为数字。后来发现这种方法的简单,强大,能轻松处理前导0和前导符号,比我用状态机高到不知道哪里去了。
此次做业以后,我才发现JAVA比C也是不知道高到哪里去了,各类内库函数,用起来都是十分方便。(以前专心致志造轮子的我真是滑稽)
虽然公测AK,可是在互测中,个人程序被找出来了bug。发现这个bug的时候我是痛心疾首,怎么有这么弱智的bug出现。
这个bug仅出如今最后的输出阶段。我在输出结果时,用一个for循环遍历到数组中最高指数的项,判断到系数不为0就输出。以前全部的项是输出 “(系数,指数),”,在指数最高的项输出“(系数,指数)”。这样有个明显的问题。若是指数最高项系数为0,那么最后一项输出会有一个该死的逗号“,”。出现这种bug,大概是由于线下自测时构造的测试样例太弱,以至于放过这种低级bug。
而下家的代码则是公测就出现了问题,互测时由于空多项式处理不当被我找到一个bug。老实说下家的dalao代码写的是比我好的,只不过处理的太多太麻烦而忽视了代码的正确性,而我只是保证了代码的正确性。
因为此次题目难度不是很大,因此我仅仅是按照测试树构造测试集来测试下家。没有发现其余错误就放弃了,改成查看下家代码,最后才发现的空多项式处理不当的bug。
此次做业比第一次的难度增长,我以为大体是由于下面两点:一是由于此次做业没有给出具体的框架,仅仅给出了五个类的设计建议。(我到如今还不知道楼层类有什么用)因此这才是真正考验咱们面向对象能力的一次做业。二是指导书的加量不加价太过明显,看着指导书就有头疼的感受,并且此次的内容也抽象的多。通常遇到这种抽象的题目什么的,我都会先去看样例,然而指导书的样例断绝了个人念头(你懂的)。万般无奈下我作出了一个如今看来十分正确和明智的决定:
花了一天来看指导书。不打开eclipse,就是看指导书。从头至尾,看的迷的地方就再看一遍。
这样作的好处是,我理解了“我要干什么”。
因此此次开始码以后,没有由于跟指导书不符而回过头大幅修改的状况。早在计组的经验中咱们就已经得知,不要轻易开始敲代码,搞清楚设计以后再开始编码,效率能提高很多。
虽然理解了总体的设计需求,以及有了大致的框架,可是想填满这五个类仍是不容易的。这时候我使用了计组的ALU策略(计组的时候要搭建CPU,开始不知道干什么,因而我从最简单的ALU写起,把全部的小部件写完以后,大致也就清晰了很多)。摸着石头过河,搞清楚电梯能干什么写出了电梯,按照这个思路把整个补充完了。
可是回过头来看,第二次做业仍是有不足的地方,因此在第三次做业以前,我修改了第二次做业的设计。由于修改的地方不是不少,这个部分没有花多长时间,可是为第三次做业算是作了垫脚石。否则按照我原来的设计,第三次做业估计得写的麻烦死。修改部分以下:
(1)存储请求的队列,本来为Array数组结构,改成了ArrayList链表结构。这样不管是取出请求,删除请求,改变请求位置,都简单了很多。(第二次做业怎么没发现这个这么好用)
(2)第二次做业中,主方法完成了从读取,到扫描请求队列,到调度的全部功能。这种设计明显偏向面向过程,主方法完成了全部功能。因而我把它拆分为两个部分。一是读取输入,并把合法请求放入队列中;二是扫描队列而且调度。并且把判断同质请求单独放置了一个方法,这样就显得更加符合面向对象的思想。并且对第三次做业的继承,也能很好的符合需求。
这么看来,第二次做业的原始稿有些惨不忍睹,因而我在这放出修改版后的类图和分析。(有些不敢想象原始版本的度量分析是什么样的。不过如今也找不到那个版本了)
其实把原来的一个main函数解决到底,改装成便于第三次做业设计要求的电梯没花多长时间。可是原来那种设计方式质量仍是惨不忍睹的,而我又没有优化,把优化时间放在了第三次做业的时候。仍是来看看优化以后的代码吧。
对标红的McCabe Cyclomatic Complexity和Nested Block Depth进行分析。
McCabe Cyclomatic Complexity:圈复杂度。圈复杂度太高的缘由是由于scheduler类承担了太多职能,既要判断输入,把合法输入塞到请求队列中,又要扫描队列,调度电梯。还有去除同质请求之类的,这么看来圈复杂度超限好像还挺正常的。这样的缺点是代码很差维护可读性差,好在此次debug没花多长时间。
Nested Block Depth:嵌套块深度。嵌套块深度表示if,for循环嵌套的个数。这个大抵是由于去除同质请求,每次拿出来主请求以后,要遍历以后的队列,这里就用到了两个for了。并且每次判断还有if-else块,因此致使了嵌套块深度太高。(我不想说以前用array的版本估计更高。由于每次去掉一个同质请求的时候,只能用for for来把以后的请求往前挪一位来去除同质请求。还好改为arraylist了否则怕是药丸)
总的来讲,此次代码写完以后基本上没出什么bug,再用try-catch来防护代码,就自觉得大功告成了。然而写出来的代码质量确是很低的,也是典型的只为了正确性抛开了优化设计的典型。事实证实,代码写完以后彻底能够有时间回顾一下写完的代码,想一想哪里能够优化,为下一次做业作好铺垫。
公测依然AK,由于此次傻瓜电梯从调度上没有什么多的要求,仅仅是判断完同质请求就搞定了。
然而我仍是太天真了。在bug树上看到本身的bug时,有一种本身被暗算,被偷袭了的感受。
此次被爆的bug是由于制表符TAB不算空格,而我会把”\\s+"(即全部空白字符)转为“”(过滤空格),因而就被爆了一个bug。
测试者把我这个bug报了还在笑,我是笑不出来,眼泪往肚子里咽。(感受这门课还能锻炼心态)
我下家写的代码就弱了不少,他第一条专门有判断是否时间为0,可是若是非法输入,会少输出一行ERROR,因而公测挂了一堆。我也是从这里找到了他的bug,至于功能性和同质测试完成的仍是不错的,由于确实不难。
测试策略仍是沿着树测下来,傻瓜电梯没有捎带,构建再强大的测试用例也并无什么用。
此次bug攻防中我知道了原来这游戏还有这种玩法?真实面向readme找bug?因此以后写readme的时候,必定要当心细致,把全部可能被图谋不轨的测试者发现的细节问题都考虑到,不在这种莫名其妙的地方被爆bug。不过以后的做业也是愈来愈难,若是仍是在这种地方找bug,那么我也是。
此次ALS电梯,写代码debug到了一点钟,星期二晚上才解决全部bug弄出来最终版,设计也算是有了眉目,能够说是十分辛酸了。
说一下此次电梯做业的时间分布吧。
1.仍是看指导书,依然花了很多时间。最重要的是弄清楚“什么是捎带”,什么状况须要捎带。
2.修改第二次写的代码,这部分真的颇有必要。(若是继承第二次的原版本估计药丸)
3.写ALS调度
耗时最长的固然是第三部分写ALS,然而前两部分的时间一样很重要。修改了第二次做业以后,如何继承就更加清晰,写起代码也就仅仅须要修改调度部分了。然而这个部分则是花了很多精力与时间,包括构思如何处理捎带,以及在实现过程当中的debug过程。由于构思的一些问题,中间我还回头修改了一点地方,好在修改的地方很少。
debug途中最难受的地方就是eclips给我带来的错误,我用下面的式子来计算目标楼层。
elv.getOnfloor() + (next_time - get_overtime) * 2;
可是很明显须要把double类型转为int类型,因而我用eclipse的快捷修改,变成了这样。
elv.getOnfloor() + (int) (next_time - get_overtime) * 2;
乍一看没有错误,结果有一段调试一直过不去,找了半天才发现是int强转的范围出错,应该是这样。
elv.getOnfloor() + (int) ((next_time - get_overtime) * 2);
像此类的debug过程还有,好比方法名叫sendInLine,调用时变成了sendinLine,等等。可见编码时的规范性和细节都十分重要。好在大的设计方向没错,最终功能性仍是很好的完成了,大概是把请求分了几类:
1.主请求,即当前请求
2.副请求,即主请求过程当中,可以完成的捎带请求
3.未完成的捎带请求(我起名为undo),即完不成的捎带请求
总之按照这个思路写,基本也是按照指导书的要求实现了捎带。
接下来从度量分析和类图来反思代码质量:
仍然是圈复杂度和嵌套块深度,此次因为功能设计,用了更多for,更多if。问题也很明显,很不直观,因此注释也是成吨成吨的加。
另一个有意思的点是圈复杂度最后的方法,第二次是sendInLine,读取请求,这里是由于须要判断不少不合法状况因此圈复杂度高。这一次变成了ScanLine,扫描队列,也就是ALS的核心部分。这部分要实现捎带,确实有不少须要添加的部分。
其实当时为了忙着debug实现功能也是写的焦头烂额,彻底没有考虑太多优化部分,想着写完了就行。回过头来看此次代码,写的是真的差。冗长,繁复。若是不是注释多我可能以后都不会看懂。只不过有了度量分析以后,可以看得更明白一点。显著的问题:
1.方法太少,一个方法巴不得能承担全部职能。好在判断同质我单独写了一个方法。
2.重复冗长。记得寒假在网上找资料学java的时候听到的一个准则,do not repeat yourself。看下这个代码彻底就是在repeat myself。包括遍历找请求的部分,我可能复制了几遍。虽然复制也就ctrl + c ,ctrl + v,可是代码质量也下滑了很多。多写方法,彻底能够减小代码量的。
此次代码是我写的最不满意的一次,以后的代码可能要吸收此次的教训,多写方法,少repeat。
这一次由于难度大了,本身测试的时间也多了,好在有较强的测试数据帮助我找到了本身的bug,顺利的de完。
这一次的测试策略大概是构造一个包含全部状况的大样例,而后一次性测试最终结果。若是不一样的话再从中找出来错误之处(我和舍友都是这样找到了本身的bug)。把功能性测试完,细节都注意到以后才算本身的debug工做完成。
此次公测仍然AK,互测并无被找到bug。虽然代码写的很差,可是所幸没有bug,这也得益于我以正确度至上的策略。
测试下家的功能性测试跟本身的策略同样,他也很好的完成了,可见也是下了功夫的。以后再看代码,找出了正则表达式的bug。
三次测试,下家功能性完成的都很不错,可是在一些细节会有些问题。好比正则表达式,这部分能够在线下测试时多下点功夫,在这方面出错仍是挺恼火的。
大概是一个菜鸡的一点感觉:
1.不要拖延。OO给的时间比计组还紧,越早开始越有充裕的时间来应付可能出现的bug或者意外状况。我比较喜欢预留一天的缓冲时间,星期三提交星期二就要写完,这样星期三就能有测试时间和debug时间,不会出现拖到DDL以后的状况。
2.多用好的工具。菜就要多学习,就拿表达式合法判断来讲,正则表达式就是比状态机强大;一样请求队列ArrayList就是比Array方便。这些东西在网上找一找资料,绝对比闭门造轮子要好。用工具来写,代码的质量和可读性都高于不用工具。
要知道,没有什么是度娘不能告诉你的。若是有,那就谷歌。
3.花时间在读指导书和构造设计是十分值得的,直接上来就写代码,可能会出现一个bug改完,又有新的bug出现的问题。读懂指导书,想好设计思路,绝对不会吃亏的。
4.多学习别人的代码。尤为是若是抽到了dalao的代码,能够好好的膜了。写的好的地方也是能够借鉴的。(直接抄代码确定是不行的)
5.个人策略是以正确性为首,不被找出bug为主要目的。其实一个代码写完以后,彻底是有时间能够反思一下本身代码的质量。哪里能够优化,哪里重复了,用一部分时间在这上面仍是能收获很多的。
6.关于互评这点仍是小小吐槽一下吧,毕竟被扣了奇怪的点,不免仍是有点不爽的。这个故事告诉咱们,readme必定要写的详细完备,哪怕没多大问题,若是被有心人找出来扣了分就很差了。毕竟防火防盗防同窗。个人策略是更偏向于花时间测试完善本身的代码,所以时间也更侧重于测试本身的代码而不是测试别人的代码。
无论怎样我以为面向readme编程,从readme里面抠错误玩文字游戏的,是有违OO互测机制的初衷的。以后的做业难度愈来愈高,但愿这样的状况能发生的更少一点。
虽然这三个星期,写oo做业仍是很是辛苦,可是收获仍是很多,好比学到了面向对象的思想,好比得到了充实的感受,感受没有虚度光阴。
至此OO的第一阶段也算是顺利经过了,若是拿游戏打比方,那么如今也才是刚刚经过新手村,前往冒险旅途的开始而已,下面的挑战难度将会更大。
但愿本身可以坚持下来,将后面的每一次做业作好。多学,多写,多想。也但愿你们能齐心合力,携手通关。
毕竟去补给站这事,你们都不想的对吧。
若是有什么写的很差的地方欢迎你们指出。