从面向过程到面向对象
——我的Java第一次作业周期总结
〇、前言
这篇博客是我对Java课程三次课后作业的总结,三次作业都是在PTA平台上完成的。正如我是一个精益求精的好学生,不将每个测试点后都打上红勾勾,晚上睡觉都不会安稳 o( =•ω•= )m 那么接下来我就来说说我在这三次作业里都学到了什么吧。
一、作业过程总结
①知识的迭代。在上学期,我们使用C语言做了不少编程题,而这三次作业也是从类似的编程题写起,先编写实现特定功能的'方法',然后就要将'方法'封装成'类'。从开始的面向过程逐渐转变成现在的面向对象,完成知识的迭代更新。
②面向过程与面向对象。三次作业主要围绕日期问题进行程序设计,总体难度渐难。第一次作业的一些小题目让先你熟悉Java的语法,第二次作业就开始设计关于日期的'方法',比如从某年某月某日算起的n天之后是哪年哪月哪日,n天之前又是哪年哪月哪日,这就和C语言的函数一样,传进一些参数,返回一个数值,而第三次作业就让你用面向对象特有的'类'来进行程序设计。这三次作业就是让我们逐渐从“给一个命令做一个动作”的面向过程程序设计过渡到“用类创造对象”的面向对象程序设计。
③遇到问题与解决问题。在三次作业中,我遇到的问题大多是某个测试点过不去。
第一次作业第四题,输入三条边的实型数据,输出三角形的类型。数据的合法性是一个考点,if-else的使用是一个考点,但这道题的坑挖在数据上。由于无法在键盘上输入根号,所以数据用的是保留小数的实型数,这时判断是否相等就要看它与结果的差值是否可以忽略,例如6.00000061与6.0就可以看作相等。于是我用if(Math.abs(b*b+c*c-a*a)<=1e-6)才过了那个巨坑的测试点。(问别人才知道的)
[第一次作业第四题题目]
在第三次作业中多次出现计算n天之前或之后的日期,若按照题目的思路,一天一天地加或一天一天地减就会有测试点超时的问题。比如今天是2020年3月27日,如果要计算八亿天即800,000,000天之后是多少年多少月多少日,那超时也不奇怪。
[用累减的方法计算n天之前的日期]
以求n天之后的日期为例,我采取的办法是先将日期设置为当年的1月1日,再用逐年加的办法加到n<=365,最后将剩下的天数加完。参考代码如下(太长了,不需要仔细看,仅供参考)
1 /*n天之后的日期,累加法超时过不了测试点*/ 2 public DateUtil getNextNDays(long n) { 3 long year = this.day.getMonth().getYear().getValue(); 4 long month = this.day.getMonth().getValue(); 5 long day = this.day.getValue(); 6 long yearT, monthT, dayT; 7 if(n==0) { 8 int yearTemp = (int)year; 9 int monthTemp = (int)month; 10 int dayTemp = (int)day; 11 DateUtil date = new DateUtil(yearTemp,monthTemp,dayTemp); 12 return date; 13 } 14 //将日期设置为year/1/1 15 long leapNum = 28; 16 if(this.day.getMonth().getYear().isLeapYear()) { 17 leapNum = 29; 18 } 19 if(month == 1) { 20 n += (day-1); 21 } else if(month == 2) { 22 n += 31+(day-1); 23 } else if(month == 3) { 24 n += 31+leapNum+(day-1); 25 } else if(month == 4) { 26 n += 31+leapNum+31+(day-1); 27 } else if(month == 5) { 28 n += 31+leapNum+31+30+(day-1); 29 } else if(month == 6) { 30 n += 31+leapNum+31+30+31+(day-1); 31 } else if(month == 7) { 32 n += 31+leapNum+31+30+31+30+(day-1); 33 } else if(month == 8) { 34 n += 31+leapNum+31+30+31+30+31+(day-1); 35 } else if(month == 9) { 36 n += 31+leapNum+31+30+31+30+31+31+(day-1); 37 } else if(month == 10) { 38 n += 31+leapNum+31+30+31+30+31+31+30+(day-1); 39 } else if(month == 11) { 40 n += 31+leapNum+31+30+31+30+31+31+30+31+(day-1); 41 } else if(month == 12) { 42 n += 31+leapNum+31+30+31+30+31+31+30+31+30+(day-1); 43 } 44 monthT =1; dayT = 1; 45 //往后推年数 46 for(yearT = year; n >= 366; yearT++) { 47 if(isLeapYear(yearT)) { 48 n -= 366; 49 } else { 50 n -= 365; 51 } 52 } 53 //往后推日期 54 if(!isLeapYear(yearT) && n==365) { 55 yearT++; 56 } else { 57 long leapNumT = 28; 58 if(isLeapYear(yearT)) { 59 leapNumT = 29; 60 } 61 if(n>=31+leapNumT+31+30+31+30+31+31+30+31+30) { 62 monthT = 12; 63 dayT = n-(31+leapNumT+31+30+31+30+31+31+30+31+30)+1; 64 } else if(n>=31+leapNumT+31+30+31+30+31+31+30+31) { 65 monthT = 11; 66 dayT = n-(31+leapNumT+31+30+31+30+31+31+30+31)+1; 67 } else if(n>=31+leapNumT+31+30+31+30+31+31+30) { 68 monthT = 10; 69 dayT = n-(31+leapNumT+31+30+31+30+31+31+30)+1; 70 } else if(n>=31+leapNumT+31+30+31+30+31+31) { 71 monthT = 9; 72 dayT = n-(31+leapNumT+31+30+31+30+31+31)+1; 73 } else if(n>=31+leapNumT+31+30+31+30+31) { 74 monthT = 8; 75 dayT = n-(31+leapNumT+31+30+31+30+31)+1; 76 } else if(n>=31+leapNumT+31+30+31+30) { 77 monthT = 7; 78 dayT = n-(31+leapNumT+31+30+31+30)+1; 79 } else if(n>=31+leapNumT+31+30+31) { 80 monthT = 6; 81 dayT = n-(31+leapNumT+31+30+31)+1; 82 } else if(n>=31+leapNumT+31+30) { 83 monthT = 5; 84 dayT = n-(31+leapNumT+31+30)+1; 85 } else if(n>=31+leapNumT+31) { 86 monthT = 4; 87 dayT = n-(31+leapNumT+31)+1; 88 } else if(n>=31+leapNumT) { 89 monthT = 3; 90 dayT = n-(31+leapNumT)+1; 91 } else if(n>=31) { 92 monthT = 2; 93 dayT = n-31+1; 94 } else if(n>=1) { 95 monthT = 11; 96 dayT = n-1+1; 97 } 98 } 99 100 int yearTemp = (int)yearT; 101 int monthTemp = (int)monthT; 102 int dayTemp = (int)dayT; 103 DateUtil date = new DateUtil(yearTemp, monthTemp, dayTemp); 104 return date; 105 }
补充一下,使用long类型而不是int类型也是为了过某些刁蛮的测试点,如果将n=2147483647(int类型的上限),即2,147,483,647天之后作为测试,那n在我的代码中会超过int的上限而得出错误的结果,所以我在其计算完成后将long强制转换成int作为返回值,才过了那个“整型数最大值”测试。一天一天加,直到加到第n天,代码虽然简单且简洁,但用巨大的数据运行起来就像只乌龟;用我的方法来计算日期,代码虽然冗长,速度则像火箭一样。这就是算法的魅力呀。 ( =•ω•= )
④作业花费时间比例。三次作业花费的时间当然是越来越长的,特别是在某些巨坑的测试点上。如果第一次作业算1个单位的话,第二次作业就是4个单位,而第三次作业至少是10个单位。
⑤编程的严谨性。编程要考虑到各种情况,认为不会有人用2147483647这种大数字进行测试这种想法是错误的。就像明明提示限制只能输入数字,我偏要输入字母,如果这时程序崩溃了或得不到想要的结果,那这样的程序写出来也不会得到认可。
二、Java设计心得
①面向过程与面向对象。在我们大一上学期已经学习了程序设计基础的课程,也完成了用C语言编写的小项目,C语言是一门典型的面向过程语言,所以我对面向过程也有一定了解;而Java是一门典型的面向对象语言,经过这三次作业的练习,我对面向过程与面向对象也有所感受。如果把编程想象成搭积木,代码越长积木搭得越高,对于面向过程而言,你每搭一块都必须足够谨慎,因为你不知道你搭错这一块会对后面的积木造成什么影响,当程序运行失败,原因也不是那么容易看出来时,你必须从头开始找起,想办法纠正它;而面向对象则像是你提前准备了装积木的盒子,你将积木搭好放在盒子中,然后把盒子一个个搭好,这样,寻找问题也方便得多。我在C语言课设时就感觉到面向过程程序设计的繁杂,我的“简易画图软件”的全部代码加起来超过1300行,设计程序时,即使完成编译后运行起来的代码也总是能出不少问题,这时我想找出错误就必须从程序开始的代码一行行往下找。而在做这三次作业时我就感受到面向对象程序设计的优势,我只要将'类'设计好,主程序想要完成什么功能,交给'类'就行了,而当哪里出错时,找到相应的'类'进行纠正就可以了。
[C语言课设作品]
②面向对象设计的基本原则。将万物看成对象,赋予对象该有的属性和功能就是面向对象程序设计的基本原则。就像我要设计一辆车,这辆车的属性有车身重量、大小、颜色,这辆车要能开动、加速、减速、刹车,当我想需要完成什么操作可以直接调用。
③Java编程思维。最重要的就是把'类'设计好,我们需要什么功能应该先想到该创建什么样的'类',而不是将功能写成方法,直接让main方法进行调用,那样就回到面向过程的老路了。使用Java进行编程就是因为它是一门纯面向对象语言,我们渴了就new一个'人'出来给我们端茶倒水。
三、测试的理解与实践
①测试对于编码质量的重要性。代码的质量很大程度受测试影响,就拿这次做的三次作业来说,如果没有测试用例要求在规定时间内要得出正确结果,我大可不必想出更快速的计算方法,直接用简单的累加法来求出日期,既省事又简洁。如果没有测试用例,我也不会想到几位小数点后近似相等的问题。站在用户的角度,如果因为好奇,输入了一个20亿(2,000,000,000)的数字,想看看20亿天之后是哪年哪月哪日,结果程序因为数据溢出告诉你一个显然错误的答案,这对用户是十分不友好的。
②测试用例的良苦用心。测试用例绝不单单用的是普遍的数据,好的测试用例是那种当自己觉得万无一失准备提交的时候,偏偏就有那么几个过不去的测试点,心中不禁惊呼:绝了!如果测试用例没有揪出某些致命BUG的话,导致用户在使用的时候程序崩溃,会极大地拉低用户对程序的好感度,毕竟谁也不会喜欢一个会崩溃的软件。所以如果让我来设计测试用例,我会着重在普通数据的测试上,极端数据也不能少,例如你要我输入正整数,我偏要测试字符串、负数、零、整型最大值、整型最小值、实型数据,看你的程序能否给出相应的提示信息。
[测试用例]
四、课程收获
①面向对象理解加深。感受到为什么现在基于面向对象的计算机语言这么流行,因为它更符合正常人的思维方式,编写代码也更有效率。
②代码健壮性理解加深。学习C语言时,老师就强调代码的健壮性:不仅要处理正常的数据,也要处理异常的数据。其中,“if-else if-else”语句尤其用得多,“将其它所有不正常的数据全部丢进else里就行了”,每次处理异常数据时都会这样想,这样,程序就不会因处理不了异常数据而崩溃了。
③提高书写博客的能力。这是我第一次写博客,以前都是有问题查百度,翻阅其他人写的博客、帖子,而现在通过这门课程,我也知道自己也可以组织语言,书写自己的博客,传授所学会的或体会到的知识,自己也在整理知识中获益,非常开心。
五、对课程的建议
干货多一点。我在观看其他教师网络讲课时,当老师们用自己理解到的知识风趣幽默地讲解出来时,我就会感觉到学习的乐趣。就像华中师范大学的戴建业教授,用极其生活化且极具趣味的语言讲述李白、杜甫、高适的交情,“找仙人,采仙草,炼仙丹”一度成为沙雕网友的笑梗。又像中国政法大学的罗翔教授,每节课都会用离奇且逗人发笑的案例使法律术语变得深刻。网红教师李永乐老师,用浅显易懂的语言讲解深奥的数理知识深得网友青睐。有趣的干货能使知识更好地得到传播。
[找仙人 采仙草 炼仙丹]
六、下一阶段的学习计划
自主学习。Eclipse有不少基本的操作还不熟悉,比如断点调试、各个界面的功能、项目的构建……接下来就要不断探索eclipse里的功能了。