OO第一单元总结
OO第一单元的内容是表达式的求导,三次作业由浅入深,考验我们的思维能力,让我们体会到了面向对象不同于面向过程的许多特点。
一、基于度量来分析自己的程序结构
(1)第一次作业
第一次作业由于题目比较简单,我完全是当作C来写的。大致思路就是用数组存下多项式的每一项,然后逐项求导即可。整个题目一main到底,也并没有用到很多面向对象的特性,并且由于原main方法过长,硬拆成了符合代码风格的多个方法,因此类结构也很丑。

(2)第二次作业
第二次作业与第一次相比多了三角函数,但每一项都可以用a*x^b*sin(x)^c*cos(x)^d的形式来表示,因此可以建立一个Unit类来表示多项式的每一项,并用Expression类来表示一个多项式,由多个Unit相加而成。而求导过程也比较简单,直接对a*x^b*sin(x)^c*cos(x)^d用公式求导即可。

(3)第三次作业
第三次作业是这三次作业中最难的一次,主要在于要实现表达式的括号嵌套。这次的类结构也比前两次要复杂很多。首先为所有表达式建立一个Expression基类,然后根据相加、相乘、三角函数、幂函数和常数分别建立子类,其中Expression类包含一个ArrayList<Expression>数组域,表示由数组元素相加而成;Multiply也有一个数组域,表示各元素相乘而成。sin和cos也各有一个Expression域,表示括号内的表达式。不过实际上Add类和Expression类的功能重合了,Add是可以删去的一个类。
由于表达式的嵌套,在解析表达式的时候需要用到递归,表现为每遇到一个左括号,就为这对括号(左括号和匹配的右括号)中的内容进行递归调用,解析一个表达式。其他解析过程与第二次作业相似。
对于求导,由于没有一个统一的形式,因此必须为每个类建立数学上的求导规则,并且这里只能采用不可变对象的形式求导,因为会存在多次的递归调用。这样会有一个缺点就是对象分配较多,可能会比较占用内存和时间。

二、分析自己程序的bug
在这一单元中我暂时还没有在强测和互测中出现过bug,就说说我在公测前的自测中遇到过的bug吧。主要针对第三次作业。在第三次作业中,虽然强侧没有被测出bug,但在强测前的10次免费提交机会刚好全被我用完了,其中出现的错误主要在括号合法性的判断这一问题上。因为递归调用需要对任意一个给定的左括号找到它的另一半,因此需要一个findPair()方法(如上图)。有了这个方法以后,还要取出两个括号间的子字符串,在这一过程我出现过bug,使得取出的子字符串存在缺失;另一方面,在判断sin和cos因子是否应该有括号这个处理上也出现过把问题想复杂的情况,使得合法性判定有错误。这两点浪费了我很多时间和提交机会。
其实,一个良好的设计结构对于bug的分析是很有帮助的。例如,如果对上图的这些子类,全都集中在一个Expression基类里,那么当产生错误时,会很难找到到底是哪一种情况出现了问题。例如,在求导过程中我打印的表达式出现了乘积项缺少括号的错误,那么很容易定位到Multiply类里面去,就不用在一个很长的类里面去找到错误的确切位置了。
三、分析自己发现别人程序bug所采用的策略
对于发现bug,我主要通过阅读程序并寻找可能的漏洞来进行。这一种方法可能是很低效的方法,每次互测都需要阅读很多份几百行的代码。不过对于学习而言,我相信阅读代码是一种好的手段,这能让我们学习别人的优秀代码,也能让我们避免踩别人踩过的陷阱。但对于互测而言,产生大量随机数据来自动化测试得分是很高效的。以后可能会尝试结合这两种方式来进行分析。
四、Applying Creational Pattern
其实这三次作业我的结构都有很大的不同。第二次作业可以说和第一次完全没有关系,并且第二次、第三次的结构组织也有很大的区别。不过虽然这两次的组织不一样,但是解析表达式的过程还是类似的,简单来说就是循环解析表达式的每一个基本项(常数、幂函数、三角函数、括号……)。对于第三次作业,我的基类是Expression类,并为所有基于Expression的类实现delta()求导方法,这样就实现了整个表达式的求导。
五、总结
通过这一单元的学习,我体会到了面向对象的基本思维,学会了面向对象的基本操作方式,不过在具体设计上还有许多可以优化的地方,希望在以后的学习中能够学到更多。
浙公网安备 33010602011771号