第一单元的OO作业就这样收尾啦,过程很艰难,但也学到了很多!以下是对本单元三次作业的分析与总结,笔者第一次写博客,肯定会有很多不足,感谢每一个戳进来看的人!

总体而言,这三次作业的目标都是表达式求导,它们的结构与难度是迭代的。第一次作业只支持幂函数的求导,第二次作业新增了三角函数和表达式因子的求导,第三次作业新增了嵌套函数的求导和格式合法性判断。这三次作业让我充分感受到了,一些问题的复杂度是层层递进的,在设计程序之前需要考虑功能的延展性,才便于后面的增量开发,减小重构的工作量。

一. 程序结构

第一次作业

第一次作业较为简单,由于只需支持幂函数的求导,我就用一个复杂的正则表达式识别了一整项,然后分离出系数与指数,然后再进行简单的合并与求导,就完成了。但是我没有考虑到功能的延展性,导致整个结构在第二次作业中完全被推翻(吐血.jpg)。

具体而言,正则表达式每匹配到一项,就新建一个Term类型对象,调用getCoef() 和 getPow()方法得到系数与指数,再将指数相同的Term合并,把所有的Term放入一个TreeMap(以系数为键值降幂排列),再进行求导就完成了。

正则表达式:

类图:

代码长度:

方法复杂度:

第二次作业

第二次作业难度陡增,增加了三角函数的求导和带括号的表达式因子的求导,不能再像第一次一样一整项地识别,需要进行重构。笔者建立了一个名为Factor的抽象类来表示因子,其中支持getIndex() 和 derivation() 方法,分别用来获取系数和求导。然后再定义Sin、Cos、Power(幂函数)、Constant(常数)、Monomial(单项式)、Polynomial(多项式)这些子类,它们都继承自Factor类,在子类中需要分别重写getIndex() 和 derivation()方法。

FactorBuilder类是读入后用来处理表达式的,其中有每一种因子对应的正则表达式,用正则表达式匹配每一种因子,以加减号分割,组合成一个多项式。

类图:

代码行数:

方法复杂度(由于本次作业中涉及的方法太多,只给出几个复杂度出现问题的类):

第三次作业

第三次作业的嵌套函数和第二次作业的括号表达式在处理方式上有相似之处。有了第二次作业的铺垫,第三次作业的难度曲线就较为平缓了。笔者依旧沿用Factor抽象类,增加了getNestedFactor()方法,获取嵌套因子,因此每一个子类需要重写的方法有:getNestedFactor()、getIndex()、add()、mul()、derivation()、merge()。

对于格式判断,首先需要用正则表达式列举出几种可能的错误类型,如果识别到这些格式错误,就直接抛出“FormatException”异常,不再进行运算。另外,在表达式解析的过程中,如果遇到不能解析的地方,也直接抛出“FormatException”异常,结束运行。

类图:

代码行数:

方法复杂度与第二次作业类似。

二. 分析自己的bug

第一次作业较为简单,在公测和互测中没有被测出bug。

第二次作业可以说是炸穿了,由于表达式处理的一些疏忽,在连续的加减号以及括号前后的加减号的处理上出现了一些问题,强测20个点只过了3个点。不过将FactorBuilder类中的replaceNumFactor()方法与replaceSubOper()方法进行一些修改,强测样例就全都通过了!

第三次作业在处理表达式嵌套上未出现bug,bug全部出现在判断格式上,本应输出“Wrong Format”的测试点输出了求导结果。针对该bug的修复较为简单,只需改正几种格式错误对应的正则表达式即可。

 三. hack策略

首先需要仔细阅读指导书,寻找可能的坑点,比如说奇怪位置上的空格、多层括号的嵌套、连续的加减号等等,提前构造一些数据。互测开始后要仔细阅读他人的代码,寻找可能的问题。

第一次互测,我们房间有三位同学被找出bug,主要问题在于空格的处理以及连续加减号的处理。

第二次未进入互测。。。

第三次互测,由于课程组规定不能提交Wrong Format的数据,而大家在表达式求导上基本做得比较好,因此我们房间没有人被hack,所有人度过了一个安详的平安夜。

由于笔者能力有限,未搭建评测机,所以hack别人非常艰难。不过研讨课上听了dalao们用各种语言搭建评测机的经验,收获了很多,以后或许可以自己动手动脑搭建一个评测机。

 四. 重构经历总结

由于第一次作业较为简单,表达式中只包括幂函数,所以考虑得很浅显,以项为单位进行识别,程序不具有延展性。另外,笔者在第一次作业的性能上也有一些没想到的地方,比如说将正项挪到表达式开头可以减少加号,使得表达式变短;还有x**2写成x*x会长度更短。

笔者认为第二次作业的最大难点就是括号的嵌套,需要从里往外层层递进,不能破坏其优先级,需要特别注意。笔者在第二次作业进行了大规模重构,先建立一个Factor抽象类,然后让每一种类型的因子都继承自Factor抽象类,再分别重写它们的求导、合并等方法,这样的层次结构会更清晰,延展性较好。第二次作业给我来了个下马威,我一度非常害怕永远栽在这里了,但是经过艰难的bug修复,也算是成功地告一段落了。

第三次作业与第二次在结构上差别不大,只增加了嵌套函数与格式判断。嵌套函数沿用第二次作业对于嵌套表达式的处理方法;格式判断原理不难,只需用正则表达式匹配几种格式错误的情况,然后在处理输入时,对于无法解析的表达式,直接抛出异常即可。但是格式判断很容易考虑不全面,漏掉一些情况,这时要全面构造测试样例,弥补疏漏。

 五. 心得体会

笔者被第一单元作业虐完了,长舒了一口气,怀着喜悦又释然的心情写下了这篇博客。虽然笔者很菜,除了第一次作业的强测全部通过以外,第二次第三次都有错,但是依然学到了很多东西,比如说用正则表达式处理复杂文本,递归下降语法的使用,评测机的搭建等等。另外,在进行测试、修复bug的过程中,我对bug的定位以及产生原因有了更清晰的认识,下次写程序可以避免一些bug。本单元作业我还有很多不足,比如说没有优化,没有搭建评测机,希望以后可以挑战一下自己,尝试一下这些内容。

另外,互测让我学习到了同学们的一些方法,也让我明白了如何去找他人的bug,什么样的代码风格是好的。另外,很感谢友善的同房成员们,秉承着“人不犯我,我不犯人”的原则,让我们度过了几个相安无事的平安夜。

在迭代式开发中,下笔前要展望一下未来需求,争取构建出合理的程序结构,避免大规模重构。但如果实在需要重构,也要撸起袖子加油干,不要消极应战。

第一单元的作业就这样告一段落了,希望未来的我可以做得更好~~非常感谢帮助过我的各位dalao!

下次再见!!!

 posted on 2021-03-29 12:10  SarahGaga  阅读(62)  评论(0编辑  收藏  举报