OO第一次总结作业
第一次OO博客作业
前言
面向对象课程已经经过了4周的时间。前三次作业全部是关于多项式求导的相关内容,内容由易到难,同时我也开始逐渐深入感受学习面向对象的各项特征,逐渐将自己的编程风格从C向真正的面向对象语言转换。同时我还接触了DEBUG和互测屋这样崭新的学习方式,在阅读别人代码的过程中不断增强自己的编程能力和学习能力。
本篇博客将结合3次作业内容,分别从题目的理解思路,代码风格和度量,BUG的产生以及修复和Applying Creational Pattern共4个方面分析我这四周以来的工作。
一、第一次多项式求导作业
第一次作业相对之后的2次简单许多,但是由于是第一次运用JAVA编写这样有一定规模的程序,对我还是有一定挑战的。
我将第一次作业大致分为3个阶段,包括多项式的格式检查,多项式的求导以及最后的化简输出。在第一步的格式检查中先检查空格部分,再将空格删除,用一长条正则匹配所有字符。在求导部分对每一项进行匹配,共有5种格式可能,分别对这5种情况进行求导,同时将结果存入HASHMAP中,最终在最后的化简输出函数中对指数相同部分,以及0,1进行化简,最终输出。
以下为第一次作业的类图:
相信这应该是我所写过的最面向过程的JAVA程序,整个程序自始至终只有一个类,并且整个程序的结构类似于C程序那样流水线的顺序结构,将所有函数以及数据都封装在同一个类里。这直接导致了在第二次作业的无法扩展,只能推倒重来。
第一次作业BUG分析
在第一次作业我的程序在测试中总共检出过2个BUG,分别为正则爆栈以及逻辑判断式中的计算顺序问题。
首先是正则爆栈问题。在第一次作业中由于第一次使用正则表达式,没有采取分段匹配的方法,而是对整段统一一起匹配,如下图所示。
由于在第一次写正则表达式时使用贪婪匹配,直接导致程序爆栈。在DEBUG中将其改为独占模式进行匹配,得以解决问题,但在风格上无疑是很不好的。因此在后2次作业中进行了逐项匹配。
第二个BUG属于比较低级的错误
问题出现在mlj2中,在BUG修复前没有括号,而判断目的是先进行或运算再进行与运算,与默认运算顺序不同,导致格式判断出现错误。
总结
总体第一次作业难度不高,但由于是第一次编写有一定规模的JAVA程序,在程序风格,重构考虑以及细节等很多地方都没有做到位,也算是给自己长了一次教训。
二、第二次多项式求导作业
第二次作业相对于第一次作业增加了sin(x)和cos(x)求导,相对于第一次作业需要增加对于sin(x)和cos(x)的正则识别,同时在求导规则和化简上增加了一定的难度。总体上格式判断与第一次求导作业相同,但了可能的三个运算符与数字的组合,需要在第一次求导格式判断的基础上增加一个新的判断函数。在最终结果方面,将每一项变为a*x^b*sin(x)^c*cos(x)^d的形式,并在最后根据情况进行化简。
以下为第二次作业的类图:
在第二次作业中我首先将整个多项式作为一个Poly类,对其进行空格检查。在删除空格后通过加减号进行划分,将整个多项式分解为各个独立的项,在对每项进行格式检查后进行求导,将求导形成的 abcd4元组变换成字符串存入Arraylist中。最后将系数项相同的部分以及1和0进行化简,最后输出结果。复用了第一次作业的空格判断函数,但在函数求导上与第一有较大差别。第一次作业使用HASHMAP进行储存,而这一次使用ARRAYLIST,于是只能大规模重写。
总体代码风格上较第一次有比较大的改善。我总共建立了2个类:多项式类和项类,在多项式类中进行空格和符号的格式检查,以及最后的化简输出工作。在项类中进行每一项的格式检查以及求导工作。但在细节等很多方面都有可以增加的地方,例如使用接口进行规范。同时我也没有让项类继承多项式类的部分特性,而是重复编写了许多相同功能的函数。以及在格式检查传递错误信息中我使用了变量传递,虽然在原理上可行,但是是不被推崇的编程方法,因此在第三次作业中通过抛出错误的方法替代了该部分的方法。
第二次求导作业中的BUG:
第二次作业在结构上并没有BUG出现,但在细节上出现了BUG。在对1进行化简时没有考虑项内只有1的情况,导致将为1的项整个消去了,产生错误。这也提醒我在编写这样有一定代码量的程序时不但要注重总体的思路和结构,还要小心这样的细节之处。同时在DEBUG时要充分考虑各种情况。正是由于这样的一个小错误使我直接掉入C档,算是吃一堑长一智吧。
三、第三次多项式求导作业
第三次作业相对第二次作业增加了多项式的嵌套情况,在求导上复杂度增加,无法只通过4元组的形式表示所有的求导结果。同时在格式判断,项切割等各个方面增加了难度,需要考虑括号等各种新的因素。程序类图如下所示:
我的程序将可能出项的结构情况大致归为3类,包括多项式类(Poly)、项类(MPoly)和因子类(Subpoly)。在多项式类中我大致进行了3项工作,包括多项式的空格以及符号检查,对多项式中项的划分以及将项的求导结果进行整合,形成多项式的求导结果。在项类中我大致进行2项工作,对项进行分割形成因子,同时将因子求导结果进行整合,形成项的求导结果。在因子类中进行2项工作,包括对因子格式的检查以及对因子的求导。在这3类之外为了方便区分系统EXCEPTION以及格式错误2种情况引起的WRONG FORMAT!,我定义了一个自定义异常DException.
由于第二次作业考虑对于扩展的需求,在这一次作业中我成功复用了第二次作业所有格式判断函数以及部分求导函数。但这一次作业在细节上仍然有很多不足之处。我的思想仍然没有彻底摆脱C的限制,在第二次作业中同样没有使用类的继承以及接口等JAVA特性的功能。同时可以从类图中看到,我不必要的属性以及类内部分方法的复杂度仍然过高,这都是我在接下来亟需转变的问题。如果仍然将自己的思想局限于面向过程中我势必会遇到瓶颈和障碍。
第三次作业BUG:
在第三次作业中由于个人能力和时间有限并没有对整个多项式进行化简工作,因此相比前2次作业在化简时的BUG,我这一成功通过了所有强测案例。同时为了避免不必要BUG的出现,我在另一方面增加了最终表达式的复杂性,方法是将所有的+转变为+1*,负号转化为-1*,但却忘记考虑了一种特殊情况,即将 sin(-23)转变为sin(-1*23),导致了互测时BUG的出现。这也提示我在编程时要从实际出发,如果一直使用这样的小聪明必定会导致意外出现。
第三次作业总结
在第三次作业中我成功实现了对前2次作业的扩展,通过递归以及进一步的划分类的方法实现了嵌套求导。但在类继承、接口实现这些JAVA特性结构的使用上仍然有很大的不足之处,同时并没有实现最终的化简工作。
四、关于互测屋和DEBUG
我对别人的DEBUG方法相对而言分为2步。第一步即在自己编写程序的过程中将可能出现的BUG记下来,然后在互测时攻击别人,其中主要包括格式错误以及可能出现的爆栈错误。例如空串,1,1-1,0*x^0等这样的常见错误。通常这种方法特别有效,将近70%的错误都可以通过这样的方法解决。第二步就是阅读他人的代码。由于要阅读将近7个人的代码,没有时间一行一行读,我采取的做法是挑选重点读,通常是匹配的正则表达式,求导过程以及最终的化简步骤等几个场景爱你犯错误的地方。通过这2步的配合90%的错误都能被找到。
在3个星期的互测中,通过阅读他人的代码我也开拓了眼界,学到了不少东西。包括工厂函数,以及优秀正则表达式书写等各项新的知识。同时也促使我充分反省自己糟糕的代码风格。
五、Applying Creational Pattern
由于使用JAVA仍然不够熟练,在3次作业中我都没有充分考虑到重构的问题。三次作业的求导过程都截然不同,全部重写。但格式判断函数,即对空格以及加减号合法性判断得到了复用。
六、总结
经过了3个星期的多项式编程,我初步掌握了JAVA的编程方法和面向对象的基本思想,目前仍有2项不足之处,首先我的思想仍然很大程度上收到C的限制,总是想通过面向过程的方法解决问题。第二是对JAVA语言的部分特性不太熟悉,当别人接口,继承,工厂函数非常熟练时,我仍然在把JAVA当C写,使用多个函数定义想解决一切问题,这显然是不合适的。在接下来的学习和编程中我需要充分认识到自己的不足,从他人的代码,网上以及课堂上充分学习,使自己成为一个合格的JAVA程序员。