面向对象第一单元作业总结

---恢复内容开始---

 

写在前面:

作为一个面向对象的门外汉+面向过程的小菜鸡,在最初开启oo作业时实在是紧张得很。然而一月有余,Idea的智能+课程的设计让我多少对oo有了些心得体会,码起伪面向对象代码来也是越来越顺手。回首看去,第一单元的三次作业其实相当仁慈,三次作业的要求逐层递进,虽然做不到面面俱到,但是也体现出老师和助教们的苦心。

一.问题回顾

本单元作业共分三次,虽然主要任务均为多项式求导,但第一次仅要求对多个形如a*x^b的项的和/差进行求导,第二次在此基础上增加了正余弦函数作为因子使得项的形式变为a*x^b*sin(x)^c*cos(x)^d,第三次则允许嵌套/复合。作业要求程序能判断用户输入是否合法,并对合法的输入进行求导+优化+输出结果,对不合法的输入输出“WRONG FORMAT!”。

二.核心步骤

2.1输入处理

在前两次作业中我的思路是对输入依次进行格式判断和分割(分项),在第三次作业中则恰恰相反,先进行分割后进行格式判断。

2.1.1格式判断

利用正则表达式检验输入格式的合法性的方法有很多,除了极易爆栈的直接靠matches硬莽之外,还有通过matcher.end()和matcher.start()判断相邻的匹配项间是否相邻、通过枚举错误格式(互测见别人用过而且居然没bug-.-)等方法。我自己在前两次作业采用的方法是先匹配由空白字符导致的非法情况,若不存在则去掉空白字符并以项来分割字符串,若分割后有子串则表明格式非法。

第三次作业的输入允许嵌套,因而单步的正则匹配已经无法奏效。于是我先对字符串进行分割,而后在递归下降的求导的过程中加入格式判断环节。由于我在分割时直接一分到底,得到的子串全部为因子(包含表达式因子),因此我直接使用了最简单直白的matches进行格式判断。

2.1.2表达式分割

在对表达式进行分割前,大家多多少少都会对字符串进行一定的“预处理”。我个人倾向于在“预处理”阶段把问题尽可能“复杂化”。就前两次作业而言,就是分别将项统一为a*x^b和a*x^b*sin(x)^c*cos(x)^d的格式,其中,若因为|a| = 1而省略了系数,则以1*x或-1*x代替;若因为x(或者sin(x)、cos(x))指数为1而省略了"^1",则手动补齐为x^1;若x,sin(x),cos(x)中某因子的指数为0,即该项中不存在该因子,则手动补齐x^0(sin,cos同理)。我自然是有我自己的一套歪理的,毕竟背着抱着一边沉,与其把五花八门的输入扔给Term类(或者随便什么地方)来进行差异性处理,不如先暴力replaceall,对字符串进行“制式包装”,然后再以某一固定符号为分割标志(这里是+和*),把最完美的项扔给下个类,让它做最潇洒的求导(插一句:replaceall是个好东西,但要慎用)。操作过程其实很简单,比如,考虑对符号的处理:三连/二连符号都可以直接转换为单独的+或者-,其中,+不变,-则替换为+-,以便通过+来分割项。全部替换之后再修正^和*后被误伤的-即可。

完成了对字符串的预处理之后,以+和*作为标志符,动一动灵巧的手指,所有标准的项就传给了下一个类。求导的过程很简单,以第二次为例,直接1个拆成3个即可。

第三次作业有一些特殊,但是同样本着“前边搬砖后边潇洒”的心态,我首先将所有处于括号内部的+替换为p,*替换为m(主要是懒得换方法,还想把前两次的复用起来...),而后递归下降,每次先以+分项,再以*分因子(若得到表达式因子则重复此步骤),在对因子进行格式检查后,投喂给对应的类,返回一个导数。由于括号内部的+和*已经被替换,在以+和*分项/因子时只会对暴露在外的子串进行操作。这其中涉及到嵌套的问题,使得某一因子可能是带括号的表达式因子,因而我将所有因子统一为表达式因子(外加括号),并在格式检查时首先进行拆括号操作(每次拆括号后都需要把暴露在外的符号变回+和*)。

仔细想来,这三次作业里我进行的操作本质上是一致的,第三次无非只是在分割后需要逐层回传+合并导数而已。(说了半天,其实也就只有输入处理这唯一的一个核心步骤。当然,代码码起来还是会有层出不穷的小问题,不过那毕竟是代码能力的问题,不是设计思路的问题(菜得真实...

三.互测刀&被刀

往事不堪回首。三次因为正则表达式”被同学两肋插刀”...不过话虽如此,哪怕身中十几刀,最后也只是扣1分而已,真正重要的还是从别人代码中汲取养分。在研究(刀人比较狠的)大佬的代码时,你不仅能丰富对oo的认识,加深对课上内容的理解,还能极其极其极其冷不丁地发现几个潜藏的bug...

3.1自己的BUG

三次的BUG全部落在正则表达式上。第一次在用\s时只特助关照了一下\f而没有考虑\v,第二次在考虑sin关键字内部的空白字符时考虑了s in和si n而忽略了s i n....第三次则是在matches时忽略了被替换为+-的-....BUG一个比一个无脑,反而更体现出了正则表达式的重要性。

3.2别人的BUG

同样,在找别人BUG时,我大多只关注正则表达式的正确性。假如有错则定向爆破,没错才开始自动生成数据暴力测。

四.基于度量来分析自己的程序结构

由于在优化时使用了大量暴力for循环、在出现一些细节性BUG时有一部分也直接使用特判的方法进行处理,导致复杂度比较高,一片飘红...下次要在这方面有所改进。

五.类图的绘制

第一次作业

第二次作业

第三次作业

 

总体来说三次的框架大体相同,内部换汤不换药,虽然存在一部分冗余的部分,但是....(实在不想重构)

 六.总结与感悟

三次作业给我的感受:第一次实现面向过程到面向对象的过渡;第二次第三次完善面向对象的思维方式、思考过程、代码架构方式等等。虽然才只是刚刚入了门,但是代码码起来也多少有了些心得。下一步要做到紧跟课程的要求和安排,加深对面向对象的理解,多思考,勤实践。

此外,面向对象相比于面向过程,给我的感受是——要更加注重框架的构建逻辑、关注各个模块本身的功能和通信。单独某个类内部的某个功能可能以面向过程的思考方式就能实现,但多个类之间的“合作关系”确实需要谨慎架构细心推导的。打代码前多思考,可以为后期调整减轻大量负担。

七.Applying Creational Pattern

(说实话在此之前没有听说过这个名词...)在这三次作业里,我采用的更偏向于工厂模式,下一步会更注重模式,加深理解。

---恢复内容结束---

posted @ 2019-03-27 12:49  月中眠  阅读(178)  评论(0)    收藏  举报