-
作业一
先放上程序的度量图和程序的类图
这一次作业之前,我对JAVA可以说还是零了解,零经验。利用作业刚开始的前一两天恶补JAVA,总算是写出了自己第一个有价值的JAVA程序。回过头来看这次作业的质量,的确不算很高。写起代码来脑子里想得最多的还是C语言,很多思想还都停留在面向过程上。每一个类里面的方法虽然不少,但是更多的是为了获取类中的私有变量,真正实现类运行功能的方法很少。比如StringOp类中,GeneratePoly方法需要连续多层调用3个本类中的私有方法;在主类中,程序的执行也是依次进行各个类的初始化,各个类之间的关系也仅停留在访问其他类的私有变量上,这种程序行为与面向对象程序并不相符。
在这次作业中我也发现,由于基本功的问题,JAVA中的很多高级功能我没有能够很好的利用,比如涉及到字符串转换为数字时,我没有使用已经定义好的方法,而是自己新写了好多行,构造了一个方法;还有异常问题,由于不适应JAVA中的异常处理机制,我自己定义了一个异常类,用于接收各种运行中的异常,并根据相应的返回值输出报错信息。这些问题虽然对程序的功能没有过大影响,但是使得整个程序多出了很多不必要的代码,显得十分臃肿。
由于这次作业整体逻辑比较清晰,自己也根据测试树构造了很多组测试样例,改掉了自己的一些笔误,因此在公测和互测阶段都没有被找到bug。
在互测阶段,我拿到的程序存在一些bug。这位同学的程序基本上完全没有使用面向对象的方法,依旧使用面向过程的方式,只有一个主类,其中有多个方法,随着程序的运行依次执行。仔细读一读他的代码,发现他虽然错了不少,但是基本上问题都是在指导书的阅读问题,比如对于正负号的支持、前导零的支持等,其他方面没有运行错误。这也给我提了醒,让我在今后的几次作业中,进一步重视指导书中的要求。
-
作业二
从度量图里面可以看到,这次作业的圈复杂度有些高。仔细分析这其实是可以预料的,电梯请求是否符合要求的几乎判断全部在Request中的一个方法内执行,导致这个方法的圈复杂度高达12。我在设计的时候感觉这些判断的逻辑都相对简单,而且彼此基本处于独立状态,就涉及到了一起。但是现在来看,还是把他们分开设计,将功能类似的判断整合进一个方法,这样在执行上也会显得更加清晰,再需要额外的判断条件时,也会更加容易。
这次作业我觉得我的一个显著进步就是应用了很多JAVA库方法。由于第一次互测分配系统的原因,我实际拿到了两份代码,除了那份有bug的以外,我还拿到了一个大佬的代码。在我阅读他代码的时候,我学习到了他使用JAVA自带的异常处理类返回异常。我把这一特性应用在了自己的作业中,使我这次作业对于输入报错与运行时报错的处理代码变得非常简洁,覆盖也更加全面。除此之外,我还尝试了JAVA中ArrayList的使用,方法的重写等特性。
由于这次作业,电梯的调度比较简单,仅仅需要在依次执行各指令的基础上,加上一些基本的同质指令判断,我在写代码的时候也就偷了一点懒,没有完全按照推荐的方法设计类和方法。这也就使得我的方法更像C语言中的函数,他们自身的功能并不是很明确,都需要配合其他方法才能实现。现在回想,我没能很好的抓住这次作业的机会进一步加深我对面向对象的理解,算是一点遗憾吧。
这次作业难度较上次有一定的提升,但是主要的关注点仍然是在输入上。我在这上面也花费了不少的时间,也改了一些bug。但是还是有一处对空格输入的处理上出现了疏忽,被同学互测的时候挑了出来。我这次拿到的同学的代码实现思路和我的有很大差别,它通过定义了很多功能分明类,比如比我多了楼层类、按钮类等等,来实现程序的功能。这种方法如果单看这一次作业确实显得稍微麻烦了一些,不过我从中也得到了启发,也看到了他在类的定义中合理和一些可以继续完善的地方。我也是通过阅读代码找到了他的程序和指导书要求不一致的问题。
-
作业三
从这次作业的类图上就能明显看出,我的整体设计思路和上一次几乎没有什么变化,因此度量超标的问题也就可以预见了。同时之前也提到了,由于上一次作业没能很好的利用面向对象的方法,而是写了一个类似于面向过程的调度器,使得我这一次作业实现起来有不小的难度。一个很明显的问题就是调度器类中,循环和条件判断嵌套过多,这是一个典型的面向过程程序容易出现的问题。由于在上一次作业中,我并没有把各个类的方法的作用分得很清楚,在本次作业中,有没有足够的时间让我对代码进行重构,因此这一次的调度方法,我只能按照面向过程的思想,在一个方法中进行大量的判断、方法嵌套等工作,从而完成较为复杂的电梯调度工作。
这次作业代码的复杂程度明显高于上次,可能的输入组合大大增加。我一开始对此也是十分茫然,不知道从何下手。我也曾尝试过从一些看上去比较简单的部分开始先写一点代码,但是随着工作的推进发现往往这些部分和自己最初的构想并不完全一致,有些甚至会涉及到非常复杂的操作。在经历了失败后,我最终静下心来,再仔细的思考程序的具体要求是什么,怎么这些要求分类,转化为可以被程序执行的多个逻辑块。这一过程的确是痛苦的,但是真正当自己想清楚之后,整个程序的处理也就变得相对简单了,在编码过程中仅需对一些细节进行优化,而不会出现方向上的错误。
这次作业由于逻辑的复杂,我的程序在刚开始的一段时间甚至都不能运行,在后期也作了多处bug的修改工作。这一次测试样例的编写工作也是十分消耗时间的,而且由于存在捎带规则,各条指令的输入顺序与执行顺序不再有明确的关系,而需要在运行中判断,因此也增加了很多种不确定的情况。在测试阶段,我的程序和我拿到的程序都没有找到bug,能明显感觉到,同学的代码质量提高了不少。
-
心得体会
这三次作业,我的成长是显而易见的。从语言能力上,我从JAVA零基础,成长为能编一些简单的JAVA程序;在面向对象思维上,虽然我对将它们应用与编程上还不够熟悉,但至少算是入了门,有了一些基本了解。
通过前两次作业同学的bug,我深切的体会到,在程序设计过程中,应当严格遵守一切基本要求。指导书就是程序设计的唯一标准,与标准不符再完美的设计也是无效的。自己辛辛苦苦工作的成果很有可能因为这些非常容易实现的基础要求而前功尽弃。未来的几次作业难度必然将会更大,要求也会更加复杂,仔细阅读指导书一定是一项必不可少的工作。
结合第二次第三次作业的情况,其实我在第三次作业中遇到的种种困境,其实与我第二次作业的不完备有着密切的联系。由于第二次的草率设计,使其扩展性很差,要加入新功能时涉及到很多的类和方法的变化,给设计增大了难度,甚至有一种在泥潭中越陷越深的感觉。这也给我将来的设计提了醒,不能忽略任何基本工作,一些在现在看起来复杂刻板的设计,在未来的程序扩展编程中可能会起到至关重要的连接作用。
同时,依照第三次作业的经验,提前对程序进行规划是十分必要的。随着程序功能越来越复杂,仅在头脑中模拟程序运行有时候显得十分吃力,在必要的时候多写写画画对思路的整理十分必要。尤其是针对面向对象的程序,更需要提前总结程序的属性,规划好各个类与方法的功能,才能写出合格的程序。
在debug上,我的经验是一边写,一边检查,同时进行一些简单的测试。在程序中难免出现输入失误的情况,只要不是逻辑上的错误,这些问题往往再扫一遍代码就能快速发现。因此在写完一个小的功能区间后,快速看一遍代码,检查有没有明显的语法错误,也就变得很有效。在逻辑复杂的部分,通过编写一些简单的测试语句,可以检查出有没有明显的逻辑漏洞,这样当程序出现bug时,可以着重检查各个代码块之间逻辑问题,而不用过度纠结于一个代码块内部是否有bug。
以上就是这三次作业的一点小小的总结与体会,与大家分享。