OO第一单元总结

第一次作业:

  第一次作业是单层括号的展开,总体来说难度重点在于如何进行表达式的解析。对于表达式我的处理是首先将单层的()**形式进行展开,然后再分析表达式、建树、求值。对于建模部分我利用两个数确定每个“基本”的因子,一个是系数一个是指数(现在看来这样写并不利于后续扩展),同时普通的因子也可以看作是一个表达式。我忽略了项那一步,认为最后的表达式是若干因子相加构成的。表达式是一个ArrayList,它里面存的就是我的因子类,然后相邻两项利用加法连接。所以总体而言在建立完成表达式树之后一切都变得相对简单。对于精度问题我直接选择BigInteger

  在bug方面由于作业要求较为清晰,情况也没那么多,所以我没有被找到bug。但是找到了一个bug,那位同学的连+-号存在着问题。

第二次作业

  第二次作业加入了三角因子与自定义函数,我对自己的因子进行了扩展,新增了SinCos类归属于普通因子内,对于一个普通的因子我定义成了a*x*(若干sincos相乘),同时在建树设立节点是增加了对sincos、函数的分析。对于函数我只需要再将他的替换结果再次送入分析类中即可获得他的表达式类,在这点上我的架构为我提供了不错的便利,但是在因子的扩展以及化简方面我的架构就十分的不友好。

  在bug方面主要是如果调用的自定义函数内部含有三角函数的话,我的sin里会有两曾括号从而导致我的正则表达式提取不出有效信息。而这个点直接让我的强测一片惨淡。这也告诉了我面对一下规则较为复杂而且很有可能存在我想不到的情况是尽量慎用正则表达式。其次在互测内大家好像都是因为自定义函数处出现的错误,所以互测方面彼此并没有发现bug

第三次作业

  第三次作业无非就是在自定义函数和三角函数内部可以实现多层嵌套。我原先的架构只需要将我的()**放到最后设立节点时解析、在SinCos内部换为一个表达式类、重写判断化简条件就完成了要求。只花了3个小时就结束了战斗。但这一次在化简方面我做的较为复杂,对于sin**2+cos**2的情况,由于我要判断内部的expr是否相等,这就需要我重新写expr的equals方法,但是equals方法又依赖于我的sin或者cos内部是否相等。。。很明显我需要设立当一个因子的Sin cos.size()为0的时候只需要系数和指数相等就可以了。之后从sincos到factor再到expr一次写好判断依据,就写好了化简。

  在bug方面,由于第二次作业时保证不会出现sum(i**2)的情况而第三次却又可能出现,但是我只注意了新增功能是否正确没有管原先要求的变化,导致了这个新bug的产生。在互测时,我输入了sin(0)**0成功抓到了一个人,但是我sum的这个bug被许多人抓到了。值得我说的是,我这一个点被几个人反复hack,着实是搞人心态。不过最好的方式是自己没有bug,最好还是自己要多做测试啊。。。。

架构分析

  由于我是一条路走到黑,我这里就直接说我最终版的架构吧。我的架构并没有太多的继承、泛化,更多的是一个类一个类之间是一种包含的关系

 

 

 

  我的部分方法复杂度太高,比如simplify函数由于我由于对hashmap等运用不熟,只好采用Arraylist,但用ArrayList时又怕内存的克隆出错,只好运用多层循环,从而导致循环的复杂度较高,而调用simplify函数的复杂度则会更高。

下面是我从网络上找到的有关的名词解释:

 

名词解释:

 

ev(G)基本复杂度,是用来衡量程序非结构化程度的,非结构成分降低了程序的质量,增加了代码的维护难度,使程序难于理解。因此,基本复杂度高意味着非结构化程度高,难以模块化和维护

 

iv(G)模块设计复杂度,是用来衡量模块判定结构,即模块和其他模块的调用关系。软件模块设计复杂度高意味模块耦合度高,这将导致模块难于隔离、维护和复用。模块设计复杂度是从模块流程图中移去那些不包含调用子模块的判定和循环结构后得出的圈复杂度,因此模块设计复杂度不能大于圈复杂度,通常是远小于圈复杂度。

 

v(G)圈复杂度,是用来衡量一个模块判定结构的复杂程度,数量上表现为独立路径的条数,即合理的预防错误所需测试的最少路径条数,圈复杂度大说明程序代码可能质量低且难于测试和维护,经验表明,程序的可能错误和高的圈复杂度有着很大关系。

 

下面是我的类的耦合情况:

 

 

  可见耦合度较高,这也是我之后要提升的。比如来说,我为了调试时方便,在建立类时违背了private精神,设立了许多Getter和Setter函数,没有使用构造函数,导致了在“上层类”中我需要很多行去将我解析出来的信息填入类中,但是这样一来带来了暴露与耦合的问题。在听课之后我知道这样是不对的,下一单元我一定要认真改正。

  下面是我的uml图,由于没有有效挖掘出他们之间的关系,于是在下列图例中我采用了Assoication

 

 

  我的主要架构一般就是一个类的某些属性就是另一个类,主要优点就是总体上看比较清晰易懂,对于程序的功能划分比较清晰,输入处理是输入处理,建树是建树,取值是取值,化简是化简。每个步骤分开执行不仅有利于写程序,更重要的事在寻找bug时通过调试可以迅速定位大概在那一方面。

  但是代价就是在改动或者调试时十分困难,需要一层一层找到最下层。类与类之间存在着耦合严重的现象,有时出现bug我需要修改多个类。这样容易造成修bug的同时造bug的情况,虽然这次我并没有造成这样的情况,但是不怕一万,只怕万一啊。

  在我的架构内Sentence类是我的字符串解析类,内设一个senExpr用来储存我的表达式解析结果。具体而言就是首先建立类的树,用树的逻辑层次来表示计算的优先顺序,之后再求值得到senExpr,之后就是我并不十分满意的simplify。

  而exprfactorSincosfuncsum则是我为了解析储存“单位因子”而建立的类。他们的功能主要有两个,一个是对输入的字符串进行解析并为自己的属性添加相关信息,其次就是返回自己的toString,而在解析的时候如果使用长段正则表达式很容易出现re,因此要谨慎选择。

  至于opNodeNodeExprNode是我为了建树而设立的类。从我第一次设立之后一直到最后我一直没动过有关代码。

bug反思

  有关于这几次出现的bug,我认为主要有以下几点原因。

  首先是不同作业的要求会发生改变,我却没有及时关注到(sum(i**2)),之后我一定要经常注意这个问题。

  其次是尽量少用一些特意化的正则表达式,一旦需求发生改变或者有某些情况发生改变,那么很容易出现bug

  值得注意的是,在自己进行的测试里,由于我的第二次作业仍然是依据大正则抓取sum函数,为了匹配到sum内可能含有的多层括号,我的正则表达式有很多“*”,本来测试是没有问题的,但是在测试“sum(i,9998877564321,9998877564322,sin(i))"时由于”*“过多导致我的正则表达式在匹配时陷入了死循环,经过网络查阅这是正则表达式自己内部匹配的问题,因此,这种bug仅凭逻辑极难发现,只能依靠黑盒测试。

  这些bug都是一些小bug,都是我没有考虑到某些情况,这也是我不注重去特殊化的后果。

  在测试别人bug时,我主要是根据要求构造一些边界的BigInterger以及sin(0)**0这类数据进行测试。同时也将自己在测试自己程序时出现bug的用例来测试他人程序,比如

+-135*+x**5*7*(-287-x**2+x**0+x**3)**+2+(+x-978++987-+715)等等

心得体会

  第一单元结束了,这一单元的训练一方面增强了我的编程能力,锻炼了我面向对象的思维。同时也让我明白了对于从过程中抽象出对象的重要性。面向对象对我也是一种挑战。在之前我没有接触过java,同时对这种难度的题目没有太多的接触,每当在苦思很长一段时间之后想出思路后总觉得对自己是一次突破,我的收获很大。但是同时我也应该注意到我的某些部分的处理并不完美,思路并不全面,这需要我在动笔之前静下心来进行细细的又全面的思索。无论如何,我都希望在之后三个单元的练习中我能继续得到锻炼,同时写完之后出现的bug少一点,调bug真的太痛苦了。

  总而言之,这单元作业让我感受最深的是架构的重要性,一个好的架构不仅可以容易扩展,更可以减少bug的产生。其次,就是要减少编程时对于问题的特殊要求。当然还要注意高内聚低耦合的特点。下一单元的作业,我一定要着重注意这里

posted @ 2022-03-22 14:12  c许七安c  阅读(162)  评论(1编辑  收藏  举报