3月份OO生存报告

充实的日子总是过得悠长而又让人眷恋,幡然回首,才发觉自己早已经再也触碰不到近在咫尺的昨天。在那淡淡的感伤之余,竟然也不由有了些许对时光荏苒的感怀。回过神来,不由摇头苦笑,心中却是少年不识愁滋味的自嘲。

毫不夸张的说,这一个月里,我每周的愿望只是活过这周。这是一个半开玩笑半认真的愿望,因为我无法确认我的能力是否足以完成OO的任务,也无法确认那样玩命的我是否能够撑下去。从某种程度上来说,这种思维夸张到让人有点无法理解——这样的事尽力就好,至于拼到那种要谈死活的程度吗?如果你的能力确实差很远的话,大不了就去补给站,何必要这样折腾自己?这样的话,我其实也在心里问过自己,而答案就是:我有我的原则,我有我的坚持,我更有着难以理喻的倔强——只要还活着,哪怕是玩命,我也要去完成任务。

如今重温这一月的经历,只觉得这于我而言算不上是什么血泪史,个中虽有不少辛苦,却也谈不上什么一把辛酸一把泪。总体来看,每次在OS的小规模袭扰下成功活过OO的大规模碾压之后,我的能力都会得到跃迁式的提高,也算是对得起自己的努力了。

作业1:多项式加法

多项式加法的任务是第一次任务,按理说应该是最简单的一次,可事实上却是它给我带来了最煎熬、最无助、最迷茫和最绝望的一周,也是它激起了我骨子里的倔强。

因为当时手头上有冯如杯自然科学论文的任务,加上错估了第一次作业的难度,把它当成数据结构编程题那种花几个小时就能大体完成的任务,所以一开始我就注定要过上惨淡绝望的一周。在舍友多次恐吓式的劝告下,我终于在任务公布后的那个周一晚上,不慌不忙地完成了自然科学论文的参考文献部分,开启了我的作死之旅。

当我看完第一次作业的指导书,我整个人都傻眼了。这真的就是让我们熟悉一下Java语言、了解一下面向对象编程的第一次作业?为什么这第一次作业的需求点和要注意的点会多到让我看了两遍都记不住数不清,而且还越想越乱?我只是周日晚上才开始学习Java语言,并且还是“探究式”地随便看了看的Java指导书,连类和方法的具体作用都分不清的菜鸟,现在就让我用Java语言去完成这种编程任务?

然而,不管怎样恐慌和无助,活还是要干的。于是我强行让自己忐忑的心稍稍镇定下来,开始做出规划。在充分了解指导书规定的需求之后,我想着先用C语言来实现这个需求,这或许会对后面用Java语言来实现需求有帮助,况且C语言是我比较熟悉编程语言,通过C语言实现这个需求会给我带来一定的信心。于是,从晚上9点多开始,时隔半年之后,我重启了C语言编程之路。

紧接着,天果然不随人愿,从晚上9点多到凌晨3点多,我经历了一段从忐忑到恐慌、从恐慌到无助、再从无助到绝望的心路历程。在这漫长而短暂的几个小时里,我不停地整理思路,换用了三四套解决方案,比如以项的次数为节点建立二叉树、中序遍历实现由低次到高次输出,或者是用数组完成对多项式的存储、计算和整理——但无论是哪个方案,当进入到深水区的时候,预估到核心功能的实现所需要的代码量,再考虑到我自己思维和心理的凌乱程度,我都只能无助又无奈地放弃,然后试图静下心来,寻求一种更简单的解决方案——然后,再次在进行到半途时无助地放弃。

最终,在凌晨3点多,我终于陷入绝望了。在深夜的背景中,我轻轻推开那放着电脑的滑动搁板,无助地起身,借着黯淡的光默默走到窗前,茫然地看着夜色下的沙河校区。我很难形容我当时的心境,也很难形容我都想了些什么。我当时很确信却宁愿自己并不确信这不是一个噩梦,因为宿舍里两位舍友高昂而没有太多规律可言的鼾声正一如既往地此起彼伏,我能够清晰地感受到心中的些许夹杂着恼意的无奈在沉沉浮浮,让我绝望得如同死水的心中泛着缕缕波澜,让我知道这真的不是噩梦。

一番胡思乱想之后,我决意倔强到底,再拼一把。我彻底抛弃情绪,出去洗了把脸,回来的时候突然灵光一闪,想起这其实可以用状态机解决——这也多亏了舍友之前无意提到“实在不行,大不了用状态机”。于是,怀着对高老板的无限感激,我精神抖擞地开始实现这个方案。一番努力之后,凌晨5点,我终于用C语言把这个状态机实现了。接着,我强忍着莫名的烦躁和困意,熬到凌晨6点实现了计算、排序和输出功能。

 

 

接下来的事情开始变得顺利许多。睡了三小时,然后勉强把上午和下午的课对付完,到了5点多,我总算又有空了。当时我感觉C语言和Java语言的基本语法极为相似,然后又考虑到自己的Java语言编程能力确实不行(如果存在的话),完全不可能做到在几个小时的时间里完成Java编程还写完Readme,所以我干脆死马当活马医,把C语言的代码粘到Eclipse,改了下输出,然后再上百度搜一下Java怎么输入,照猫画虎给搞了一个,就这样Java版状态机完成了,整个过程顶多10分钟,与C语言编程的用时完全不成正比——虽然Java版代码只有一个Class,而且Class中只有一个方法main。当晚,我参照指导书进行Debug,在凌晨2点Debug完成之后又花一个多小时写了份Readme,总算是把任务完成了。

最终,这个在状态转换之中夹杂着大量其他操作的状态机没有辜负我的心血,公测全过,互测也没出问题。倒是系统给我匹配的估计是位转系的“巨灵神”,而且还是搞竞赛那种,逻辑超清晰,代码写得超简洁,除去注释空格,也就170行左右。遇到如此代码,还趴在Java入门的门槛上挣扎着想爬下来的我完全是错愕的——搞什么鬼,新手村都能遇到满级号?所幸一位舍友把这份代码借走拿去观摩,然后很巧地发现其中两个很小的bug——貌似是因为把第一个多项式单独处理时,考虑不周。再然后,这位“巨灵神”就被我一新手号屠了两刀……

作业2:傻瓜电梯

吸取了第一次作业的教训,对于第二次作业我算是有了些准备,所以完成任务的过程中也就少了许多艰辛,不至于像第一次那样差点把自己玩死。

这次作业,我不确定自己是否依然是面向过程编程,但看起来起码比第一次好了很多。这次我用了7个类——规定的5个类,加上Main以及Print类,不过,每个类当中似乎都只有一个方法……我的设计思路大体是Main类的main方法获取输入内容,对输入内容进行格式匹配,格式匹配成功的ER请求分配给elevator类,FR请求分配给floor类,格式匹配失败则报错;elevator类和floor类负责对输入内容进行分割处理,判断输入内容是否合法,若合法则将其信息存储到数组中,合法但重复则输出提示信息,非法则报错;随后main方法将数组交给request类,由request类收录新请求;输入结束后,request类将收集到的请求交给QueOfReq类,QueOfReq类负责不同时刻产生的剔除同质请求并生成新的待执行请求;新的待执行请求将被交给Scheduler类执行和输出。

在这次作业的过程中,我大致了解了类、类的方法和类的实例化,但除了弄清楚由类实例化的对象的生命周期,与将它实例化的方法的执行周期相同以外,我并没有太多的感悟。我甚至觉得,这次作业中我将数据交给类来处理,然后由类返回处理后的数据,再将处理后的数据转交给下一个类来处理,像这样的做法,其实是把类当成函数使用,与C语言编程的不同之处仅仅在于C语言的函数调用另一个函数,被调用函数处理完数据后就“死了”,而调用它的函数还继续“活着”;Java的方法将类实例化,这个实例却能和该方法“共死”,看起来“活得”比函数久一些。

 

总之,且不说代码写得怎么样,这次作业的完成过程还是蛮顺利的。可惜,这个顺利没能持续太久。公测结果出来后,我挂了两个点,因为我在elevator类把判断ER请求的楼层数非法条件写成了(floor<=0)&&(floor>10)——没错,就是&&,不是||。这主要是因为我深夜码代码,心情、状态都不在线,而FR类请求和ER类请求在判断内容合法时,条件基本相同,所以我把floor类判断FR请求内容合法的部分复制了过来,然后进行了一些修改,修改的时候却没有改到位。更为可惜的是,这次的顺利让我似乎有些太过自信,而舍友也顺便帮我进行了大量测试,结果都没问题,所以我最后没有对程序进行覆盖性测试。最终,悲剧就这样发生了。

福无双至,祸不单行,这次作业的不顺没有止于公测。互测部分,因为Readme的疏忽,我被挂了三个点,其中一个点是ER请求楼层数非法造成的,经过申诉之后被撤销。这次的Readme是我在深夜对指导书进行草草复制粘贴加修改写成的,写的时候差不多是想起什么要特殊说明的地方,就顺手加上一行,这样很容易会造成疏漏——而结果恰恰证明了这一点。

总结这次作业出现错误的原因,无非都是因为深夜进行无脑的复制粘贴修改造成的。加上事先没有罗列要点,事后没有进行覆盖性测试,这样都能不翻车才怪。吸取教训之后,在第三次作业过程中我采取了一些措施,总算没有重蹈覆辙,还顺便让舍友躲过一劫,不过这是后话了。

这次我匹配到的同学依然是“巨灵神”级别的(基于Readme的信息,我甚至知道他是谁),只是我拿到的是这位同学的代码初级版。但哪怕是初级版,其中“对象套对象”“方法返回对象”等手法还是让我感到眼花缭乱。而这份代码中的明显的bug在公测中已经测出来,别的bug则几乎不存在。也许是天不亡我吧,在我抱着学习的态度阅读他的代码之际,猛然想起他对输入的楼层数字的长度是不限制的,但是又没有对其进行超出int范围的处理……借此申报两个Error之后,我在这次互测总算是没吃亏。

作业3:ALS电梯

这次作业,我做得有点磕磕绊绊的,过程算不上顺利,结果却也不至于像上次这么惨,但是还是暴露出一些别的问题。

也许是受上次作业写出bug的刺激,这次我在周六上午就迫不及待地着手研究指导书了。可惜,结果却并不是那么地好,关于捎带请求方面的判断,我完全凌乱了。等到周日晚稍稍理清思路,我决定不采用扫描整个队列的方法,而是将请求“放”到对应楼层,然后让电梯“一层一层走”,每到一层就扫描该层请求,判断捎带和同质,我认为这样的方法在逻辑上更简单,编程上也更易于实现——虽然步骤可能比较繁琐。

在周一晚把想法实现的时候,我遇到了不小的麻烦。我在实现的过程中用了许多的数组,但数组的下标与数字并不是直接相等的(1层的请求存在数组的0下标列),此外数组存储的只是请求的下标,并不是请求内容本身,请求内容又分别存储在多个数组当中……就这样,我成功地被自己创造的凌乱关系弄乱了,码代码的时候也不得不将许多本来可以合并的部分分开实现,以做到“一目了然”,防止出错。最后的编程结果是我在上次作业的基础上,对QueOfReq类进行了大幅度修改,还增加了一个newScheduler类和一个GetState接口,其中GetState完全是为完成任务而设。QueOfReq类则负责生成待执行请求序列,同时剔除不同时刻产生的同质请求,它是程序最为核心的部分之一,包含了多个方法,分别负责电梯上下、下行和同层STILL情况下的捎带和同质处理;另一核心部分则是newScheduler类,负责执行请求序列和输出,一样包含了多个方法,分别负责电梯上下、下行和STILL状态下的运行和输出。最终,当我完成编程的时候,从整体上看我的代码已经变得凌乱不堪了,很多地方出现重复和冗余,补丁也是随处可见。

 

所幸,这次的代码没有枉费我为了打各种补丁所付出的心血,成功通过公测,互测也没有出问题。而这次我匹配到的依然是“巨灵神”,并且他的代码写得漂亮到让我叹为观止,以至于不忍心下手。最后我报了一个随手测出的100条请求的bug,然后就欣赏这份代码去了。

总结这次作业,我认为结果看起来也许不错,但过程却不理想,其中的许多本来可以避免的麻烦都是我给自己找的。此外,因为时间分配不合理,我还在OS课程遭遇了大麻烦——我本来可以把周六用来完成OS的任务,这样既可以完成别的任务,也可以避免因为独立钻研初版指导书过深造成思路凌乱。

心得体会

(1)倔强活下去,我的毅力和潜力不会让我失望。经过三次作业的持续碾压,我意识到这将是一场马拉松而不是百米冲刺,所以除了竭尽所能以外,我还需要做好坚持到底的心理准备。而通过这个月里我的收获可以看到,只要坚持活下来,那么新的我将会比现在的我在能力上强上无数倍。

(2)要合理安排时间。这是一场马拉松,不是靠三两天的玩命就能彻底摆平的;此外,我还要应对来自OS以及其他课程的袭扰,并不是只要专注于此。

(3)方法很重要。比如做规划的时候,最好遵从一定的方法;做测试的时候,心里也要清楚该怎样确保万无一失;测试匹配到的不同对手的时候,怎样基于对方的等级和代码风格更快更准地确定找bug的方案,也是有讲究的……

(4)一定要把战绩保持好!这个很重要!为什么我能次次匹配到“巨灵神”?不就是因为战绩不糟吗?如果让我匹配到像我一样的对手,写出来的代码跟我一样乱七八糟惨不忍睹,那我要怎么办?那读代码Debug的过程不就变成了加强版的“if-else型”短文改错?那样我怎么通过观摩优秀代码来学习Java编程?

posted @ 2018-04-02 19:27  16061054  阅读(167)  评论(1编辑  收藏  举报