OO第一单元总结

OO第一单元总结

一.基于度量分析程序结构

第一次作业

第一次作业需要完成的任务为简单多项式导函数的求解。

思路分析

这次作业比较简单,只需建一个Item类存放每一项的系数和指数,再化简输出即可。具体思路是先正则判断整个输入,再去除空格以及化简连续正负号为一个,然后建立Item类,正则提取每一项存入Item类数组中,求导,再遍历数组合并同类项,最后输出。输出时为了优化可先特判结果是否为0,否则再遍历数组找一个符号为正的项先输出(如果有),最后根据系数和指数输出其他项。

类图

复杂度分析

总结

虽然说难度不大,但是第一次写OO还是基本写成了面向过程。。。而且写的一些方法复杂度也高,没有考虑代码复用的问题……并且从后两次作业来看第一次的架构完全不合适,几乎要完全重构。另外判断整个表达式果然出现了正则爆栈,不过幸好讨论区给出了独占模式的解决办法让我没被查出bug再就是对空文件输入没用`hasNextLine()`,不过也没被查出来~

第二次作业

第二次作业需要完成的任务为包含简单幂函数和简单正余弦函数的导函数的求解。

思路分析

这次加上了sin(x)cos(x),不过本质上没有太大区别,只是比上一次多做一步提取项中因子。由于上一次爆栈的教训,这次对项做正则检查,然后拼接起来与原输入长度比较是否相同来判断WRONG FORAMT!然后同样将输入部分做空格和符号的规范化简,再放入Item类中。这次要存储的数据有系数和三个因子的指数,我选择用ArrayList<BigInteger[]>的方式,为每一项建一个数组,然后做乘积求导,新生成的三个元素加入list并删除被求导的元素,再遍历list合并同类型,最后输出。

类图

复杂度分析

总结

把整个表达式放进Item类是不合适的,这次设计依然不OO,且对第三次的设计几乎没有帮助。对于存储方式的选择hashmap可能比arraylist好些,因为判断同类项时我用了大量条件判断,而用hash只要用key就行。另外应该保持原list不可变,将求导出的结果放入一个新的list中,这样使程序更合理,同时减少出bug的可能。优化方面没有什么好思路,只做了$sin(x)2+cos(x)2=1$和$1-sin(x)2=cos(x)2,1-cos(x)2=sin(x)2$这些,写了两个很烂的youhua(),youhua2()方法,复杂度极高。。不过将大部分操作封装进Item类里也算是OO方面的一点进步吧。

第三次作业

第三次作业需要完成的任务为包含简单幂函数和简单正余弦函数的导函数的求解,包含嵌套因子和表达式因子。

思路分析

这次作业太难了。由于包含任意数目的括号和表达式因子,正则判断变成一个大难题,甚至单个因子的正则表达式都难以写出,不过这也提供了思路,因为能写出来的只有幂函数和常数因子的正则,这两个刚好是整个表达式的基石,于是可以采取递归判断直至这两个因子的方法。

首先通过栈的方式将所有最外层的一对括号替换成一对大括号,于是可以用"\\{.*?\\}"这样的正则表示表达式因子和嵌套因子,然后对输入判断不含非法字符后就可直接对忽视括号内部细节的表达式做WRONG FORMAT!判断,写成方法isExpr()。再借助大括号提取括号中细节判断是否为因子,这里同样要先替换最外层小括号为大括号以便继续递归,写成方法isFactor()。对于提取出的因子中若还有括号,则再提取括号中内容做isExpr()判断,直至最后因子为常数因子或幂函数。

求导部分同样采取变大括号的方法,这样可以写出表达式和项的正则,建立Expr类和Item类,然后依次提取Item中sin{...},cos{...},{...},幂函数,常数因子,建立Factor父类,再相应建立SinCosExprFactorBase类这些子类,Expr.dev()调用Item.dev()Item.dev()调用Factor.dev()Factor类中建立Expr对象,直至最后调用Base.dev()

类图

复杂度分析

总结

这次作业最大的难点在于最初的思路,以及想到替换括号对其他操作进行简化。由于开始思路不明,程序有些地方没有写全面,导致最后完成时出现了很多bug,甚至正则表达式都复制出错漏了一项。。不过这次写出了继承这样比较OO的设计,方法设计也合理,没有什么复杂度特别高的(除了main里判断WRONG FORMAT!的部分)需要改进的是求导方面,毕竟直接输出字符串可拓展性不高,而且完全没有做优化,因为在目前架构中实在太不方便了。

二.分析自己程序的bug

前两次没有被找出bug,第三次被找了不少。强测挂了一个点,是由于判断因子的正则漏了表达式因子的部分,导致对第一个因子为表达式因子的输入错判为WRONG FORMAT!

互测还被找出提取括号中内容的一个bug,因为太关心括号,忽视了因子带指数的情况,substring定位不准,改用spilt就很好的解决了问题。

其实这两个bug多测几组数据自己很容易发现,与设计结构没有太多关联,但因为花太多心思在架构设计上,就没有重视细节,改到能过中测的程度就偷懒直接提交了,懒得优化也懒得检查。。。所以以后写程序还是不能太随性,至少要用互测的方法先把自己的程序过一遍。

三.发现别人bug的策略

第一次互测的时候没有经验,真的仔细看了很多代码,主攻正则,然而并没有找到很多bug。后来看到讨论区的交流,也弄了一个自动生成表达式和集体对拍的脚本,但是没什么效果,最后也就找了三个。

第二次看到一位同学写了800多行,直接没了看代码的欲望,然后就用来sympy库,把脚本升级成自动对拍的了(但是要10s才能测一次),确实省了很多时间也找出不少,但最后发现全是同质的。。。于是开始手写一些格式错误的输入,比如在各种地方穿插space和\t,各种地方连续正负号,真的找到了对\t判断不全的bug。

第三次仍像上次自动生成,虽然写不出嵌套的表达式,沿用第二次的生成器,还是找出不少bug(鲁棒性自测很重要)。然而禁止了WRONG FORMAT!的互测,对拍器都是同质bug效率不高,我选择构造复杂度表达式因子和嵌套因子,找到了-+(--x)*1这样一锤四的好样例,结果这次反倒找出来不少。

四.Applying Creational Pattern

前两次作业比较简单,我只用了两个类,应用不了创建模式,但第三次作业的Factor类可以。

应用工厂模式,创建一个Provider接口,再创建四个工厂类,分别对应Sin,Cos,ExprFactor,Base四种因子的创建方法。这样做可以提高程序的抽象层次,若有新的需求,比如增添一种因子,就可新建一个工厂类,不需对程序做太大改动。

posted on 2019-03-27 21:23  ture117  阅读(120)  评论(1编辑  收藏  举报

导航