OO第一次博客--前三次作业分析:
第一次作业:
第一次作业的要求是实现有一定鲁棒性的多项式加减法。对于大多数刚开始接触JAVA语言和OO思想的同学来说,这次的难点主要是:JAVA语法、面向对象思想、正则表达式的使用和程序的鲁棒性。相比以为的语言,我无法理解“面向对象”这个词的含义。在膜拜已经对java有所理解并上过面向对象先导课的大佬们的代码后,我才稍微对“面向对象”的写法有所理解。虽然听起来很不现实,但在了解了一个语言的基础语法后,参观和学习大佬们的代码似乎是快速上手的好方法(这似乎与课程要求相违背但对于学习确实有所帮助)。在听学姐讲解后,有听说正则表达式是一个便利的工具,便利用之。对于程序的正确性以及如何保证不crash,除了自己多加try来注意,还需要大量的测试验证了。毕竟自己测得不够全面,就只能期望别人也不帮你测。。。
在设计上,我采用了一个Poly类型的数组Polylist来存放各个合法多项式,在首项前加“+”,再利用找操作符号来分割各项进行操作。这是一种常见的操作,效率算不得很高,但好在不至于超时而且很便于理解。
以下是其类图及其度量分析:
从度量分析中看出的是Match方法被标红;该方法是本次作业中我的主方法。。。
(附:McCabe Cyclomatic Complexity(圈复杂度)用来衡量一个模块的复杂程度,统计一个函数有多少个分支(if,while,for等),没有的话复杂度为一,每增加一个分支复杂度加一。圈复杂度的作者McCabe认为,圈复杂度在3~7为比较好的结构化方法,圈复杂度大说明程序代码可能质量低且难于测试和维护。Nested Block Depth(块嵌套深度)则为嵌套深度。这两块出现超标,往往说明程序设计有缺陷,或部分代码嵌套深,难以判断逻辑,或直接写成了面向过程的思想。)
作为一个菜鸡的第一个java程序(除了HelloWorld),我代码中的问题很多:
首先是对java语言的不熟练导致处处像C,也直接导致了一个函数到结尾(就像main)。另外因为初学面向对象编程,导致代码中对于对象的重视不够,更多则是在面向过程。。。
而自己被爆出的bug中也体现了自己对代码的理解不深刻:被人爆数组(公测同样在爆但侥幸逃过一劫),对方刻意构造大型错误输入,瞄准我在错误输入处理时想当然的随意开了一个小数组来储存结果,被爆两组数据。这也让我在之后的两次作业中debug和找bug时对于代码中的数字更加重视。
第二次作业:
傻瓜电梯的设计与验证。傻瓜电梯的难点,应是对电梯的设计上,即如何实现电梯、分别给五个或者更多的类什么功能、各个类之间如何串联等问题上。我采用了dipatcher类对操作进行处理;而电梯类elevator和floor分别存储电梯在该指令执行完成前后的时间、楼层、运动状态,并给调度器计算指令完成时间。指令demand负责读入,在work函数进行输入筛选处理后将可执行的传进指令队列,再从头开始逐条传入dipatcher取出处理。
这次的作业相比第一次作业,面向对象的思想体现的就明显多了;指导书中对于多个类的提示也在把我们从面向过程的误区往出拉。
以下是其类图及其度量分析:
从类图中能看出demand类几乎是没有起到任何作用,因为只是在work函数对输入进行暂存,进行筛选之后直接就传给queue了。。。甚至没有都可以。。。这带来的问题也十分明显:queue类过于庞大了,在第三次作业中更会有所体现,这又导致了我的数据结构复杂冗余,原本demand中应该实现的分类只能在queue中狂开数组来分类保存。。。在调度时也麻烦的一逼。。。
好在作为第二次作业,相比上一次的青涩少年我也是有了第一次经验了。。。在数据处理上稍微严谨了一些,不幸地是,这次我被爆出的问题比上次还要多:
- 对分支结构的处理太过傻逼。在处理错误输入时,因为经验不足,面对诸多错误情况自乱了阵脚。。。一大堆的if,break,和flag自增在公测的几个小数据面前就开始瞎几把输出(对错误判断后的处理太混乱),好在为第三次提供了宝贵的参考。
- 采用了奇怪的计数和循环:do-while和一个从0开始的count,判断条件里的是[count-1]元素。。。有一个事先考虑大条导致了只有一个RUN的时候数组越界(count-1<0)。。。
- 对指导书的理解不深刻:指导书中对于“第一条指令时间不为0按crash处理”的描述,被我简单的理解成了直接报错结束进程。。。结果挂了两组公测数据。。。也是参考。。。
度量分析中红色的是新加入的度量类,几乎是代码中的核心处理部分,说明了我对于指令的处理还是应当有所精简。
第三次作业:
学长口中的第一个“不好写”:ALS电梯。
这次电梯的最大改动为允许捎带,这就出现了主指令和最多两条捎带指令(即若存在捎带,能找到一条最先捎带的指令,以及可能会找到一条和它仅指令标识符不同的指令一起被捎带)。因此排在后面的指令有可能被先完成,不能单纯只从从队列头开始向后一次遍历。将所有指令按楼层进行储存。再使用了一个指令队列,规定头指令为主指令,再每变动一层后判断同质,向后找最优捎带指令,执行后将其标记,不再执行。当所有比主指令先执行完的捎带指令全部完成,执行主指令并从队列删除,将新的主指令置顶。循环下去至队列为空。然而在完成代码的时候,还是被炸出了一些奇怪的bug(主指令为同质指令时没有将其筛除,说到底还是判断逻辑不够完备)。此外,要求使用对于我们菜鸟来说新学习的继承、接口、重写。。。(然而惭愧的是自己代码中几乎没有对这些的体现。。。接口无用,继承基本全是重写。。。)
作为单线程第二次电梯作业,她已经向现实中的电梯有所靠拢。。。同时对于我们第一次的电梯要求更高了(得先调好第一次才能避免第二次出现上一次的bug)。遗憾的是还是出现了问题(上面已提到)。。。
以下是其类图及其度量分析:
度量中体现的还是老生常谈的问题:depatcher的庞大。而导致这些的原因之一是对数据结构的组建太混乱(第二次中的queue在本次中不减反增)。。。
好在debug方面总算把第二次的问题解决了,可是测试数据太弱还是没能发现一些特殊的问题,比如提到的主指令为同质。。。以上这些原因这也导致了我后来de了好久也没de完。。。
至于心得体会,从一个菜鸡的角度来看有以下几点吧。。。
- 基本语法得学明白。。。Java作为新的工具,欲善其事不利其器是绝对不行的。。。不然就会出现像我一样申明数组却没有没有挨个实例化的de了好久bug的傻叉行为。。。
- 打出提前量;周二晚上写肯定写不完,除非你通宵。。。
- 多向大佬们学习;这很重要,菜鸡闭门一个月造的车也不一定跑的过大佬三天写的sports car。。。毕竟一个月的学习和大佬几年的积累还是没得比,面对人家的丰富经验,我们还是要多学习。。。(遗憾的是很多大佬并不愿意分享代码)所以我们要多接受大佬的点拨和教育,这是我们尽快走向熟练甚至成熟的不二之法。