BUAA_OO 第一单元博客总结
一、作业分析
第一次作业
构建思路
第一次作业要求比较简单,仅是幂函数表达式的求导,因此程序的实现基本是面向过程。设计了三个类:Main,Strcut,SinStr。
Main类兼具了多项式类的功能,负责获取多项式,把它传给Strcut进行多项式的去空格和标准化(去掉多余正负号并把‘**’换成‘^’便于分割)接着,Main类把多项式分成项并传入SinStr(SingleStr)中,由SinStr进行项的分割和求导。这种方法面向过程,扩展性差,直接导致了第二次的重构。
度量分析




可以看到虽然第一次作业较为简单,但是由于面向过程的痕迹太过严重,还是导致Main类的平均循环复杂度高了。
类图


第一次只有三个类,关系比较简单。
Main:处理多项式分成项并输出。
Strcut:处理空格、多符号、和标准化
SinStr:进行项的求导
bug分析
第一次作业在互测和强测均未被发现bug,也未hack到别人。看同房hack数据别人的bug主要是大数问题、连乘问题和多符号处理的问题。
第二次作业
构建思路
第二次作业增加了三角函数和表达式因子,我的设计也还是比较基于面向对象。主要分出了表达式(加法求导)、项(乘法求导)和因子三个类,由于因子类中的内容:sin,cos和x形式比较统一,故因子分为两类:一类是表达式因子,另一类采用了四元组的形式,用abcd四个变量分别表示常数和三个形式的因子的指数,方便计算和简化。另外如果遇到了表达式因子,就调用新的表达式类进行求导。同时为了更方便判断表达式因子,我将sin和cos的括号都提前去掉了。
劣势:
- 由于需要用到item类对项中的内容进行拆解并传达给因子项,所以item项显得很臃肿。
- 可拓展性依旧不高
- factor的求导函数直接print结果且设定了新的私有变量作为求导后的数值进行保存,实际没有必要设计新变量,直接输出;更好的方法是返回字符串,在main或者新类中统一输出,这样也能进一步化简。
**优势: **
- 因子项的(偷懒)设计使得简化较为简单,在读取过程中已经有了一定程度的简化。
- 已经有了初步的框架,也有了第三次分离出各因子项的思路
度量分析


第二次作业因为类的功能分散了,所以类的循环复杂度反而要低于第一次作业。
类图


Main:读入字符串
Polynomial:多项式求导,分割出项
Item:项提取判断两种因子,分别给另外两类
Factor:其他因子的求导
bug分析
虽然一开始中测过了,但是晚上想简化一下。。还没注意时间。。还化简出了bug。。就没进去互测。(血的教训,一定要注意时间!!!)
强测交上化简前过中测的代码后发现还是有两方面的bug:
- 在求导结果为0的时候,没有任何输出
- 没判断多项式因子前可能存在的负号,主要原因是匹配多项式因子时只匹配了括号。改正的方法是在读入该因子的时候判断一下前面的符号,存入该符号的信息。
第三次作业
构建思路
这次思路非常清晰,按照助教给的思路,多项式类(实现加法求导)、项类(实现乘法求导),因子用工厂模式分出了常数类、sin类、cos类、幂函数类、表达式因子类,其中三角函数类中加入了嵌套求导的实现。表达式因子类调用表达式类的求导,三角函数类调用了因子类的求导。但是由于太过复杂,放弃了化简。
对于WF的判断,因为前几次都进行了预先的格式化简,这次想顺着之前的思路做,就先进行了空白字符和替换字符的判断,再进行替换。
有待提高:
类之间的耦合程度还是有点高,周五研讨课上听大佬的分享,发现sin,cos,x都是幂函数,可以单独创建幂函数求导的类。两个三角函数因子也可以继承自一个三角函数父类。
由于做的方法不太好,三次作业没有用hashcode进行化简,这个方法也用得不熟,可以尝试学习一下。
其实如果正则表达式写得完整一些,完全不需要预处理,可以减少一个类和判断条件的大量判断复杂度。看起来也更加简洁。
度量分析:


第三次作业明显更加复杂,复杂度更高。由于事先针对特殊情况优化了多项式,使得判断信息需要的条件过多,增加了复杂性;耦合度不够,导致有些重复的代码也是代码臃肿的原因之一。
类图


Main:读取表达式,创建表达式项
Polynomial:加法求导,创建Item项
Item:乘法求导,创建Factor项
factor:工厂模式创建各因子项,并作为父类被继承
ConstFactor:常数因子
CosFactor:cos因子,创建Factor类
SinFactor:sin因子,创建factor类
PowFactor:幂函数因子
PolyFactor:表达式因子,创建表达式类
bug分析
互测中,由于没有搭评测机,没有被hack到也没hack到别人。自己的问题主要是在于对于括号数目不对等时没有判断出WrongFormat以及特定情况未分离出多项式因子的问题。
另外,WrongFormat判断是一个难点,hack的时候输入了一些WF的数据,有的程序未判断出WF,跑出了结果。(可惜不能提交)虽然WF的情况有很多种,但是只要好好匹配多项式和因子的格式,就能解决掉许多判断。
二、重构经验
一个好的框架可以让写代码轻松不少。
第一次作业的时候,未考虑到之后的作业中会出现诸如表达式因子之类的要求,所以做得比较简单。
第二次作业进行了完全重写,大大缩减了main函数。这时候已经有基础的分类思想了,分为了多项式、项、因子类,表达式因子所需要的递归下降是最大的难点。第二次作业的构思和完成花了我大量的时间,主要的时间还是花在了递归思想的建立和所需的面向对象的形式。
第三次作业我也进行了重构,不过自认为难度与第二次作业相比较小,原因是第二次作业中已经掌握了这样的方法。第三次只需要将因子扩展成各自的类,再让三角函数因子调用因子类即可。
代码的构架是个人思维方式的展现,私以为代码的层次结构越清晰,也代表着作者的思路清晰,这一点和计算机组成有相似之处。有的时候在编写代码过程中还是摸索着一点一点写,缝缝补补敲出一份满是补丁的代码,一旦写完,思路顺了下来,便觉得十分清晰。所以若是代码比较凌乱,最好在刚写完的时候进行重构,这样能较快完成重构。重构完成后,再进行功能增加也比较容易。
三、心得体会
首先,应该重视第一次的作业,这次没有重视第一次的作业,使第二次作业的工作量增大。第一次作业往往展示了这一单元的大体构架是什么,搭好基本框架,认真思考他需要考察的逻辑。
做作业的过程是学习新知识成长的过程,从原来什么都不会到运用正则表达式匹配、学习递归下降,运用工厂模式,复写父类方法,为了完成作业,查了许多网页资料,大佬们的讨论也使我收益匪浅。对于新知识的应用也让我对他有一定的了解和记忆,我也应该去试着用一直以来不太会的hashcode的方法,走出舒适圈,用更简洁高效的方法。
对于测试bug,应该多多尝试涵盖各种类型的数据,不需要很多超长的爆栈数据,因为这次我产生的基本是可以简化为只有10多个字符的bug,化繁为简也是我改bug时的思路,一点一点删掉多余项和括号,定位自己的错误。在debug阶段,有人思路清晰,代码性能好,这样的代码bug少,debug起来也比较难;有的人相反,代码乱,输出很长,不易分析,不会搭评测机真的看着脑袋疼。要hack这样的代码,也应该构造尽量简短的数据,减少自己的负担。
浙公网安备 33010602011771号