OO第一单元总结

2021 OO第一单元总结

1. 代码架构与度量分析

1.1第一次作业

1.1.1基本思路

   第一次作业比较简单,因子只有常数项与幂函数两种,且表达式模式单一:因子通过“*”连接构成项,项通过“+/-”连接构成表达式。

   先将表达式的字符串预处理,达到以“+”作为项的分隔符的效果,而对于每一个项,都可通过计算简化为 (常数项*x**指数) 的形式,之后只需将多个项交给表达式统一求导相加即可。

1.1.2代码分析

1)类图:                    

                                                                             

     Expression:

          属性:full:表示该表达式的字符串

                     Map:存放Term,key为项中x的指数   

         方法:analys:解析表达式,将表达式拆分为项存储

                   printanswer:将存储的项求导、优化、相加输出

     Term:

          属性:full:表示该项的字符串

                    term:常数项

                    exp:指数

         方法:calculate:解析自身字符串,计算出常数项与指数

 

2)度量分析:

  代码规模分析:

   第一次由于要求较少,代码行数较少。

 

  类复杂度分析:

    

 Expression类复杂度很高,原因是受面向过程编程习惯的影响,把类内有的方法写得过长,完全可以拆分。

 

   方法复杂度分析:   

   

可以看出Expression.prinanswer复杂度很高,原因是把求导、化简、输出全部放到了一起,通过大量条件语句判断各类情况

3)作业分析

    优点:整体来说基本具备面向对象的思想,思路清晰。Expression类只负责解析,将字符串拆分成项后交给Term类,Term处理自身后交还给Expression类统一管理

    缺点:个别方法处理上还是面向过程的习惯,导致方法冗长;

               没有考虑增量开发,后续作业只能重写;

 

1.1.3bug分析

    在优化输出时,众多情况中,对于x**2求导后只留下x这种情况,常数项与x之间忘记加“*”,导致所有出现x**2项的数据点全部爆炸

    问题出在了圈复杂度较高的printanswer中

 

1.2第二次作业

1.2.1基本思路

   本次作业加入了三角函数与表达式因子,也就是说存在嵌套的情况,不过sin和cos还只有最简单的sin(x),cos(x)情况。

   每一项仍然可以化为统一形式:常数*x**(x指数)*sin(x)**(sin指数)*cos(x)**(cos指数)

   将表达式和项和因子全部看成为Func类,用map管理多个上述统一形式,key为(x,s,c)分别表示三种指数,key对应值为常数

  采用递归下降处理嵌套问题,由于当时对继承、接口等理解不够透彻,故没有采用清晰的架构处理,而是在递归解析字符串的过程中通过Func中定义的add、sub、mult方法直接计算,得到新map

  这样在递归完成后,即可得到一个已经拆完括号并合并后的表达式,该表达式由多个“常数*x**(x指数)*sin(x)**(sin指数)*cos(x)**(cos指数)”项组成,通过map管理,只需逐个求导相加输出即可

 

1.2.2代码分析

  1)类图:

          

    Func类:

          属性:map:存储化为统一式 常数*x**(x指数)*sin(x)**(sin指数)*cos(x)**(cos指数) 的多个式子

         实现了加、减、乘法,支持任意Func间的计算,可以生成新map

   Expression、Term类均视为Func类,无特殊功能

   Factor类:

          继承自Func类,当匹配到最简单因子时可以调用其构造方法

   Match类:

          文法分析器,用于按照文法递归下降匹配表达式、项、因子

 

2)度量分析

      代码规模分析:     

                

      由于把Factor,Term,Expression全部统一为Func,由Func实现所有功能,可以看到Funcl类代码规模较大。

    

   类复杂度分析:

  

  可以看到Func,Match两个类复杂度较高,因为表达式、项、因子的全部功能均由Func实现,全部分析构造均由Match实现

  

   方法复杂度分析:

   

   可以看到Func.print和Match.matchFactor两个方法复杂度较高,主要是这两个方法的实现较为面向过程,存在大量if语句枚举,没有进行划分

 

3)作业分析

    优点:就本次作业而言,我认为我的方法是比较好的,很好的将所有项、表达式、因子化为统一形式,用map管理并实现map间的运算,在递归下降的过程中直接计算,直接得到去括号并合并的表达式

              性能上比较好,从的得分来看大部分数据能得到很高的分数。

   缺点:具体方法仍旧有面向对象的习惯,且这次虽然可以将所有类统一化,但没有考虑增量开发,下次仍旧要重写。

 

1.2.3bug分析

     为了优化,直接将常数项为0的项从map中删去,导致结果为零的数据没有输出。

     这个bug感觉不是某个方法的问题,是确实忘了有输出为了0的情况

 

1.3第三次作业

1.3.1基本思路

    本次作业作为表达式求导的最终版,要求支持三角函数嵌套、三角函数乘方,仍旧采用递归下降,按照类型层层构建,实现每个类的求导。

    通过hashmap管理来实现合并,重写所有类的hashcode,equals方法

    在之前作业原有类基础上,对于每一种因子(常数、幂函数、三角函数、表达式因子),建立类,全部继承自Factor,覆写求导方法。

    至于格式问题则只需在两处判断,一个是递归下降到最底层时若没有成功匹配则WF,另一个是匹配完成后若字符串还为匹配完全,则WF

 

1.3.2代码分析

1)类图:

    

   Factor类:

          属性:指数exp

         是众多因子所继承的父类,类中定义求导函数,供子类覆写。

   Expr类:继承自Factor

         属性:hashmap 管理 Term

         表达式类作为项的上一级需要通过hashmap管理项,同时作为因子需要实现求导(多项求导相加)、输出等方法

   Term类:

         属性:hashmap管理Factor

                   constant单独存储该项的常数部分,同时也方便项之前的符号决定加减,若为减号,常数部分乘-1即可

        Term类通过hashimap管理Factor,项的求导为乘号相连的因子求导

  Sin,Cos,Pow,Constant类:继承自Factor

        这些类除了个别属性不同基本相似,作为各种因子实现求导方法,其中Sin,Cos的求导为嵌套求导

  Match类:

          文法分析器,用于按照文法递归下降匹配表达式、项、因子

2)度量分析

    代码规模分析:

    

还是Match的老问题,把所有的匹配方法全部放在了Match中

 

 类复杂度分析:

可以看到Term,Expr,Match复杂度较高,Term,Expr输出与简化没有分开,求导也因为格式问题存在条件判断的情况。

Match则由于文法变得更加复杂,需要更多的判断。

 

方法复杂度分析:

可以看到,Match.matchFactor,Term.getDerivative复杂度较高。

 matchFactor匹配因子时涉及到所有种类因子的判断与匹配。

 Term的求导函数则因为是多个因子相乘求导且直接转换为字符串,所以涉及多种条件判断。

 

3)作业分析

    优点:对于表达式的解析采取了较稳清晰的架构,同过hashmap实现化简,解析的同时化简,求导则直接转换为字符串,最后再对求导后的字符串解析化简并输出,不需要其他化简方法

    缺点:虽然不需要独立的化简方法,但就是由于把太多的工作放在了一个类或者方法中,导致个别类或方法过于复杂,容易出错,分工不够独立化、不够清晰。

 

1.3.3bug分析

   没有考虑到括号不匹配的问题

   化简和解析同时进行导致代码复杂,出现细节问题

 

2. 发现别人Bug采用的策略

     限于个人水平,不会用自搭评测机,采取的手测的方式。

     首先,测试自己在作业过程中重点考虑过的bug可能数据

     然后随机读代码判bug,根据代码的架构,以及看起来较乱的部分重点测试(虽然结果来看并没有收获)

 

3.重构经历总结

     与其说重构经历,不如说重写经历,虽然有意的熟悉、尝试了面向对象编程,尽量将工作分工给各个类,但由于缺少对后续拓展的考虑,导致每次都是重写。

      第一次作业不存在表达式因子,整个表达式只有表达式、项、因子的单项结构,直接使用正则表达式便可做到解析。

      第二次作业使用了递归下降解析表达式,想出自认为比较巧妙的统一形式,并通过map管理与计算,性能分较高,但是没有考虑后续sin,cos的嵌套情况,使得程序没有可扩展性。

      第三次才算正式构建表达式的层次架构,层层管理,在基本理解了继承、覆写等的基础上勉强解决了问题,基本算踏入了面向对象的大门,但是对于分工仍旧不明确。

     整体来看,对于类的建立已初步具备面向对象思想,但是对于方法的定义还是受面向过程的影响,总想着把多个工作同时在一个方法中完成,导致代码复杂。

     重构时应着重注意方法间的独立性。

 

4.单元心得体会

           由于假期没有充分预习,第一单元一路走来可谓是充满艰辛,对于难度增长较快的第一单元(尤其是第一到第二次),在思考作业如何完成的同时,还要努力地习惯Java

     这个新语言,学习list,map的用法,hashcoed等方法的重写,继承、接口概念的理解,来不及为后续考虑,导致每周都要重写,工作量挺大的。

           但在一顿摸爬滚打中还是度过了第一单元,学到了许多东西,在压力下快速熟悉了Java,基本掌握了各类集合的用法,对接口、继承、覆写等有了实践基础上的理解,理解并掌握

    了递归下降的算法,找到了点面向对象编程的感觉,可以说收获满满。

          对于第一次和第三次作业,性能其实都还行,但由于细节问题导致强侧有些数据点没过,最终得分并不高,挺可惜的,之后的作业需要更加的细致,不能只满足于不靠谱的中测,      自己多进行测试。

           与同学讨论是个很棒的学习方式,大家各自分享自己的思路,互相参考可以借鉴的思路,对完成作业很有帮助。特别是对于我这种没有充分预习,还在摸索阶段的同学,在研讨课

    这种大佬分享经验的场合基本插不上话,课下与水平相似的同学互相讨论一起学习真的很有帮助。

     

posted @ 2021-03-28 19:58    阅读(112)  评论(0)    收藏  举报