OO第一单元总结——表达式化简

目录

1 基于度量来分析自己的程序结构

1.1度量分析

1.1.1 类的属性个数、方法个数、类总代码规模

1.1.2 方法规模、控制分支数目与复杂度分析

1.2 分析类的内聚和相互间的耦合情况

1.2.1 内聚性分析

1.2.2 耦合度分析

1.3 架构

1.3.1 第一次作业

1.3.2 第二次作业

1.3.3 第三次作业

1.1.4 自我评价

2 架构设计体验

2.1 第一次作业

2.2 第二次作业

2.3 第三次作业

2.4 自定一个新的迭代情景,并说明你的最终设计在这个新迭代情景上的可扩展性

3 分析自己程序的bug

3.1三次作业的Bug分析

3.1.1 第一次作业

3.1.2 第二次作业

3.1.3 第三次作业

3.2 分析

3.2.1 对比分析出现了bug的方法和未出现bug的方法在代码行和圈复杂度上的差异

3.2.2 思考可以通过怎样的方式来降低方法的复杂度

3.2.3 思考与总结

4 分析自己发现别人程序bug所采用的策略

5 分析自己进行的优化

6 心得体会

7 未来方向


1 基于度量来分析自己的程序结构

1.1度量分析

        由于三次架构没有做出过大的调整与重构,本次分析主要基于比较全面的第三次作业代码。

1.1.1 类的属性个数、方法个数、类总代码规模
属性个数方法个数属性个数方法个数
MainClass01DeFactor13
Lexer47ExponentialFactor23
Parser24FuncFactor23
PreProcess01FuncDefine22
NumberFactor14Mono311
VariableFactor14Poly210
ExprFactor23Token23
Term26Expr14

        从分析结果可知,代码规模最多的类有Mono类(219行),Poly类(168行),Lexer类(128行),Parser类(115行)。其中Mono(单项式类)和Poly(多项式类)作为表达式最基本形式,其中包含大量的计算方法、求导方法以及转化为字符串方法,因此行数较多。

        其次就是Lexer类以及Parser类,二者作为递归下降的表达式解析的功能类,其中包含表达式词法分析、语法分析解析方法,面向过程性较强,故代码规模较大。

        还有一个值得注意的就是自定义函数的处理类(FuncDefine),其中包含两个功能性方法,一是自定义函数的定义,即将读出的自定义函数转化为字符串按照函数名分别储存起来;二是自定义函数的展开,即在解析表达式阶段,将自定义函数因子带入具体的参数转化为纯粹意义上的因子,存储为FuncFactor。这两个方法面向过程行比较明显,

        其他类作为数据结构,例如表达式类、项类、因子类等,都是作为面向对象的类,包含的方法不太涉及功能性,故代码规模较小。

        总体来说,各个类的代码规模与其本身的面向对象/面向过程特性有很强的关联。

1.1.2 方法规模、控制分支数目与复杂度分析

参数解释(来自网络)

CogC: Cognitive complexity,认知复杂度,用来衡量代码被阅读和理解时的复杂程度。每种控制结构的使用都会增加认知复杂性,而且嵌套的控制结构越多,认知复杂性就越高。

ev(G): Essential complexity,基本复杂度,用来衡量程序非结构化程度,ev(G)高意味着非结构化程度高,难以模块化和维护。

iv(G): Design complexity,设计复杂度,与方法控制流与对其他方法的调用之间的相互联系有关,也代表了将方法与其调用的方法进行集成所需的最少测试次数。

v(G): Cyclomatic Complexity,圈复杂度,是通过每个方法的不同执行路径数量的度量,可以看作是完全执行方法控制流所需的最少测试次数。圈复杂度 = 1+ if、while、for、do、switch cases、catch、条件表达式、&&'和||的数目。

        很明显看出来我Mono类中的toString方法复杂度显著大于其他方法。这个方法用于将单项式即

转化为字符串。

        为了实现最简化,我傻瓜式地分类讨论,系数是否为0?指数是否为1?为0?exp的底数是否为0?面向过程化过于严重,这是程序需要优化的一个点。

        同理,在Mono类的求导toDePoly方法的复杂度也很高,我同样是傻瓜式分类讨论。其他标红的方法有语法分析类的ParseFactor()方法,Mono中实现exp()字符串转化的方法等。 我们同样能得到上一节的结论,即面向过程性强的方法通常复杂度较高。

1.2 分析类的内聚和相互间的耦合情况

参数解释(来源网络)

OCavg: Average operation complexity,计算每个类中所有非抽象方法的平均圈复杂度。继承的方法不计算在内。

OCmax: Maximum operation Complexity,计算每个类中非抽象方法的最大圈复杂度。继承的方法不计算在内。

WMC: Weighted method complexity,计算每个类中方法的圈复杂度总和。

1.2.1 内聚性分析

        可以看出各个类的复杂度与我们之前的分析基本一致,FuncDefine类、Mono类、Poly类、Parser类以及Lexer类的复杂度较高,说明这些类内的内聚性较高。

        其中FuncDefine类、Parser类以及Lexer类都是面向过程性的类,其中的方法多为功能性方法,且通过分类讨论解析表达式,故复杂度较高,类内的过程内聚性高。

        Mono类和Poly类中包含计算、字符串转化、求导方法,后两者在上述的说明可知,我都是用傻瓜思维对其分类讨论,复杂度必然是高的,同样是说明类的内聚性高。

1.2.2 耦合度分析

        由我的UML类图(见下图),可以明显看到,解析表达式过程中的Lexer、Parser以及Token类之间紧密相连,层层相关,耦合度高。

        数据结构部分,Factor作为接口,与所有的Factor因子类相关联,其次,Term由Factor构成,Expr由Term构成,再者,因子部分很多类又包含表达式Expr,故可看出这些数据结构也是错综复杂,关联性强,故耦合度高。

        计算与输出部分的Mono类与Poly类中,Mono中包含一个Poly属性,Poly又有Mono构成,二者紧密联系,耦合度高。

        由此可以分析,不同模块里的类耦合度较高,在不同模块之间也是相互联系的。

1.3 架构

1.3.1 第一次作业

        在第一次作业中,我的代码架构基本形成与定型,其中包括预处理阶段、递归下降阶段、表达式解析阶段、数据结构、计算阶段、字符串转换等。

  • PreProcess类:预处理阶段

    将读进的字符到PreProcess类进行预处理,首先处理空白字符,使接下来的预处理更为简便,接着去前导零,最后去双符号,因为有了之前空白字符的除了,我们可以直接replaceAll,例如:

    input = input.replaceAll("-\\+","-");
    input = input.replaceAll("\\+-","-");

    同时要注意会出现“--+”等情况,所以要replaceAll两次。

  • Token类,Lexer类与Parser类:递归下降与表达式解析

    • 基本是按照oolens公众号以及实验代码改写的。在Token类中,枚举了8种token的类型。

      NUM,ADD,SUB,MUL,LEFT,RIGHT,POW,VAR

      其中,POW部分,我将^index(即指数符号与指数)看作一个整体处理。

    • 在Lexer词法分析类将表达式分为一个个token。

    • 在Parser语法分析类,采用递归下降的方式解析表达式。

  • Factor类,Term类和Expr类:数据结构

    • Factor接口:因子,其中包含了NumFactor,ExprFactor以及VariableFactor。

    • Term类:项,将项看作各个因子的乘积,因此,在此类中用ArrayList保存项的因子,其中sign表示此项的符号(正负一),符号的判断在语法分析阶段。

    • Expr类:表达式。将表达式看作各个项的和,在此类中用ArrayList保存表达式的项。

    • Mono类:表达式最终化简结果的单项式,根据题意,最终Mono的表达形式为

       

      其中a为系数,i为x的指数。

    • Poly类:表达式最终化简结果的多项式表达,Poly为多个Mono之和,因此在Poly类中,用ArrayList储存Mono。

  • Mono类和Poly类:计算

    计算在Poly类中进行,其中:

    • AddOrSubMono方法:将一个Mono加入这个Poly的ArrayList<Mono>,其中我们要判断ArrayList中是否含有同类项,由于表达式较简单,只需判断指数是否相等。

    • AddOrSubPoly方法:在AddOrSubMono方法的基础上,进行Poly与Poly之间的加减计算。

    • MonoMultiplyMono方法:进行Mono与Mono之间的乘法,系数相乘,指数相加。

    • PolyMultiplyPoly方法:在MonoMultiplyMono方法的基础上,进行Poly之间的乘法计算。

    • PolyPower方法:在PolyMultiplyPoly方法的基础上进行Poly的乘方计算。

  • Mono类和Poly类:字符串的转换

    这一步我们分为两个过程:

    • 首先在Mono类中对单项式进行转化,根据系数是否为零,指数是否为0,1分类讨论输出。

    • 然后在Poly类中对Mono.toString进行连接,最后与预处理一样,把双符号化简,同时把开头为0+去掉。

    • 即可得到最后结果,输出。

1.3.2 第二次作业

        在第二次作业中,作业要求新增了exp以及自定义函数部分,对应的,我在整体架构上增加了函数定义部分,函数因子,指数因子,以及对应的函数解析,指数运算等部分。

  • FuncDefine类:函数定义与参数代入

    包含了两个功能方法:Define与Extend。

    • Define:将读到的函数表达式储存起来,因为函数名一定不同,所以我将函数名与函数表达式、形参联系起来,即利用HashMap<String,String>存储函数表达式,HashMap<String,ArrayList<String>>存储形参列表。

    • Extend:已知函数名以及实参,就可以从HashMap获得对应的函数表达式,再将实参代替形参,这样就可以获得一个表达式的字符串。

  • FuncFactor类:函数因子类

    其实函数因子的本质可以看作表达式因子,其中包含两个属性:func : String和expr : Expr

    • func表示表达式中的自定义函数字符串,利用FuncDefine类中的Extend方法进行扩展得到一个表达式的字符串。

    • 对以上的字符串进行词法与语法分析,即可得到表达式(Expr),接着就可以利用expr的toPoly转化为多项式,与其他因子进行融合。

  • Exponential类:指数因子类

    包含expr(Expr)和index属性,其中expr为解析后的表达式因子,index是指数。在构造器中,将exp()中的表达式字符串进行词法分析、语法分析,得到Expr类型的expr底数,这样利于之后的计算。

1.3.3 第三次作业

        本次作业在上次作业的基础上增添了求导因子。在整体架构上,我在每一个数据结构类中增加了求导方法,新增了求导因子类

  • 求导因子类

    • 包含一个expr(Expr)属性,代表求导因子中的表达式因子。

    • 在Token中新增DE类,修改Lexer和Parser中的方法,实现对求导因子的识别。

1.1.4 自我评价
  • 优点

    • 功能模块逻辑清晰,预处理、解析表达式、计算等模块功能较为独立,利于模块测试。

    • 不同模块的内聚性较强,模块内的类之间耦合性较高。

  • 缺点

    • 部分类内的方法分支过多,不利于测试,可以适当化简。

    • 分支重复代码过多,需要适当提取,简化分支。

    • 没有优化结果,导致性能分的缺失。

    • 没有认真思考细节问题,例如,指数需要用bigInteger存储,前导零处理不当等。

2 架构设计体验

        在第一次作业中,我代码的主体架构已经成型,在后两次作业中以添加、修改计算方法等为主,没有大规模的修改已有架构。以下便是我在每次作业的架构迭代中的一些修改与想法。

2.1 第一次作业

        第一次作业中,我的主体架构已经包含了预处理部分、递归下降部分、解析表达式部分、单项式多项式的计算与转化为字符串部分。

  • 预处理阶段

    将读进的字符到PreProcess类进行预处理,首先处理空白字符,接着去前导零,最后去双符号。具体实现已写在上文。

  • 递归下降与表达式解析

    • 基本是按照oolens公众号以及实验代码改写的。在Token类中,枚举了8种token的类型。

      NUM,ADD,SUB,MUL,LEFT,RIGHT,POW,VAR

      其中,POW部分,我将^index(即指数符号与指数)看作一个整体处理。

    • 在Lexer词法分析类将表达式分为一个个token。

    • 在Parser语法分析类,采用递归下降的方式解析表达式。

    • 在后续的迭代中,若有新增的因子,仅需新增Token的枚举,以及在词法语法分析是多加考虑新增因子的识别与解析。

  • 计算

        计算在Poly类(多项式类)中进行,其中:

    • AddOrSubMono方法:将一个Mono加入这个Poly的ArrayList<Mono>,其中我们要判断ArrayList中是否含有同类项,由于表达式较简单,只需判断指数是否相等。

    • AddOrSubPoly方法:在AddOrSubMono方法的基础上,进行Poly与Poly之间的加减计算。

    • MonoMultiplyMono方法:进行Mono与Mono之间的乘法,系数相乘,指数相加。

    • PolyMultiplyPoly方法:在MonoMultiplyMono方法的基础上,进行Poly之间的乘法计算。

    • PolyPower方法:在PolyMultiplyPoly方法的基础上进行Poly的乘方计算。

  • 字符串的转换

         这一步在Mono类和Poly类中分为两步进行:

    • 首先在Mono类中对单项式进行转化,根据系数是否为零,指数是否为0,1分类讨论输出。

    • 然后在Poly类中对Mono.toString进行连接,最后与预处理一样,把双符号化简,同时把开头为0+去掉。

    • 即可得到最后结果,输出。

2.2 第二次作业

        在第二次作业中,作业要求新增了指数函数因子以及自定义函数部分,对应的,我在整体架构上增加了函数定义部分函数因子指数因子,以及对应的函数解析指数运算等部分。

  • Mono类与Poly类的修改

    由于引入了新的因子,需要把多项式Poly修改为为形如

     

    单项式Mono类增添多项式Poly项以记录exp的指数表达式,即Mono类中包括了系数coe,幂函数指数index和exp指数函数中的多项式,其转化为String时为以下形式。

     

    由于基本形式的改变,计算方法、toString等方法均要做出调整。其中遇到最大困难是单项式的合并问题、深克隆问题,在以下部分细说。

  • 单项式合并问题
    • 首先说明,我的Mono类中包含Poly属性,而Poly类中包含Arraylist<Mono>属性,二者相互嵌套。

    • 最开始,采用最基本的重写Mono和Poly的equal方法,但是最后会出现情况:exp(x)exp((3*x))会被合并。出现这个问题的原因是:Mono判断可以合并的条件是x的指数相等和exp的底数相等,其中exp的底数我用Poly保存,即判断Mono中的Poly是否相等。

      接着就到了Poly的判断,即x(3*x)是否可以合并,前者的ArrayList中包含一个Mono因子:x,后者包含一个Mono因子:3*x,由于这两者x的指数和exp底数均相等,按照Mono的相等判断方法,二者是相等的,所以程序认为Poly是相等的,从而exp(x)exp((3*x))是可以合并的。

    • 针对以上的问题,我发现x(3*x)的系数不同,所以我在Poly类中增加了一个HashMap<Mono,BigInteger> monoCoe来储存Poly中各个Mono的系数,在判断Poly是否相等时会同时比较系数,在以上出错的那一步,就不会判断Poly相等,从而不会误判exp(x)exp((3*x))是可以合并的。

      public class Poly {
          private ArrayList<Mono> monos = new ArrayList<>();
          private HashMap<Mono,BigInteger> monoCoe = new HashMap<>();
          ...
      }
  • ToString方法修改

    由于exp()的特殊性,即底数必须为因子,所以在部分非因子的情况下需要添加括号,这里我新写了一个方法判断底数是否为因子,其中使用正则表达式对特殊情况进行判断。

    • 首先是变量因子,例如x,x^2等,我们用一下正则表达式判断。

      String isVar = "(x)(\\^\\d)?"
    • 其次是常数因子,我们用一下正则表达式判断。

      String isNum = "(\\+|-)?\\d+";
    • 最后是指数因子,最初我使用以下正则表达式判断:

      String isExp = "(exp\\()(.)+(\\))";
      

      即判断是否为exp(...)形式,但是,在最后的测评中出现问题了,它会将exp(x)+exp(1)也识别为正确的(因为这也是exp(...)形式),但是由于我对正则表达式的掌握程度不高,不知道如何构造正确的正则表达式,所以我对方法进行修改:

      我摒弃了String isExp = "(exp\\()(.)+(\\))";的判断,将表达式内第一个出现的exp()因子变为x,在exp(x)+exp(1)例子中,即将字符串转化为x+exp(1),这样显然不会判断为因子。若其确实是exp()因子,则整个因子都会变成x,依然会被判断为因子。

  • 函数嵌套处理

    • 我选择在Parser语法分析阶段处理,采用的是从外到内层层递归的方法。

    • 首先在词法分析中,根据括号的个数,我将最外层函数表达式的','转化为'@',例如,将f(f(x,y),x)转化为f(f(x,y)@x)

    • 在Parser部分,就可以用'@'进行分割,得到外层函数的实参,这样层层嵌套递归后就可以解决函数嵌套的问题。

2.3 第三次作业

第三次作业在第二次作业的基础上新增了求导函数,对应的,我在整体架构增加了求导因子,以及各个因子、项、表达式、单项式以及多项式的求导方法。

  • 因子、项、表达式求导

    • 最基础的是因子的求导,根据数据特性,进行求导,引入toDePoly():Poly方法,求导后得到Poly类型的数据。

    • 项求导,利用乘法法则,其基础也是因子的求导。

    • 表达式求导即为各个项的求导之和,进行PolyAddPoly计算即可。

  • 本次作业的最大难点在于嵌套求导如何实现?

        本来未在Mono和Poly类中实现求导功能,但是对于求导因子自身的求导(即嵌套)无法实现

        因为求导因子内部的表达式求导完为Poly形式,为了实现嵌套,必须对这个Poly继续求导,所以在思考下,又在Mono和Poly类中增添了求导方法。

        则在求导因子内的toDePoly方法即可写为:

public Poly toPoly() throws CloneNotSupportedException {
        return expr.toDePoly();
}
public Poly toDePoly() throws CloneNotSupportedException {
        return expr.toDePoly().toDePoly();
}

2.4 自定一个新的迭代情景,并说明你的最终设计在这个新迭代情景上的可扩展性

  • 若有新增的因子,以去年作业中的sin,cos为例,其实处理起来和指数因子类似。首先要在Token中新增SIN,COS类型,再对Lexer和Parser做出相应的修改。新增SinFactor和CosFactor,其中的属性也为表达式,与指数因子类似,接着就是修改Mono和Poly的属性、计算方法、字符串转化方法等。

  • 若有多个变量,也是对Token、Lexer、Parser作出对应的修改,同时在VariableFactor类中新增name属性,来判断多变量的名字,同时要修改Mono和Poly的属性、计算方法以及字符串的转化方法等。

  • 可以发现,我的架构在新的迭代中也具有可扩展性。

3 分析自己程序的bug

3.1三次作业的Bug分析

3.1.1 第一次作业
  • 前导零问题

    判断失误,很简单的判断如果当前位为0,后一位为数字,则去零,直接导致了100变成10,103841变为13841,这是非常严重的bug,导致在第一次强测和互测都被hack了。

    后来发现,去前导零简直多此一举,所以我索性将其删除,因为在读数字阶段,字符串转化为数字,前导零会自动被消除。

3.1.2 第二次作业
  • 深克隆问题

    在本地测评时,发现了深浅克隆问题,Mono在运算过程中没有深克隆,导致其系数、底数的改变,所以在Mono类和Poly类中增加了深克隆方法。

  • toString正则表达式

    对于指数因子,最初我使用以下正则表达式判断:

    String isExp = "(exp\\()(.)+(\\))";

    即判断是否为exp(...)形式,但是,在最后的测评中出现问题了,它会将exp(x)+exp(1)也识别为正确的,所以我对方法进行修改:

    我摒弃了String isExp = "(exp\\()(.)+(\\))";的判断,将表达式内第一个出现的exp()因子变为x,在exp(x)+exp(1)例子中,即将字符串转化为x+exp(1),这样显然不会判断为因子。若其确实是exp()因子,则整个因子都会变成x,依然会被判断为因子。

  • 函数代入扩展中的exp

    本地测评时,exp()中也包含x,在函数实参替换形参的过程中,要避免exp的x被替换。所以首先将exp都转化为eap,在进行替换,最后再将eap还原为exp。

  • Mono和Poly的equal方法

    最开始,采用最基本的重写Mono和Poly的equal方法,本地测评是出现:exp(x)exp((3*x))会被合并。(具体原因见2.2部分)

    所以我在Poly类中增加了一个HashMap<Mono,coe>来储存Poly中各个Mono的系数,在判断Poly是否相等时会同时比较系数,在以上出错的那一步,就不会判断Poly相等,从而不会误判exp(x)exp((3*x))是可以合并的。

  • 指数问题

    强测中的(((((((((((x^8)^8)^8)^8)^8)^8)^8)^8)^8)^8)^8)^8由于我的指数用int存储而爆了。😢 所以我将所有的index都改为BigInteger,在Bug修复阶段又出现了以下问题。

  • 未重新修改equal方法

    将所有的index都改为BigInteger后,Mono中的index同样也被修改为BigInteger,但是由于没有重写equal方法,又出现了问题,所以又重新生成equal方法。

3.1.3 第三次作业
  • 求导求错了

    是令我最痛心的!这个错误导致我强测只有50+,没有进互测屋。

    在Mono求导时,系数写错了,例如dx(exp(x^2*exp(x)))会得到2*x*exp((x+x^2*exp(x)))+2*x^2*exp((x+x^2*exp(x))),对比正确答案:2*x*exp((x+x^2*exp(x)))+x^2*exp((x+x^2*exp(x))),发现后一个项的系数是错误的。

  • 但是但是但是!!可怕的是,跑测评机没有跑出来,至少提交过十次,而且事后我又测评了十几次,均没有发现问题。所以不能太依赖测评机,要自己多构造数据,回到代码本身,多多检查。😩

3.2 分析

3.2.1 对比分析出现了bug的方法未出现bug的方法代码行和圈复杂度上的差异

以上Bug大多发生在这几个方法:

  • Mono类的toString方法

  • Mono类的toDePoly方法

  • FuncDefine类的extendFunc方法

图片数据来源于 1.1.2 方法规模、控制分支数目与复杂度分析

        我们可以发现,这些方法的复杂度都爆红了,而且代码量大、分支多难以进行测试

        在这些方法中,我都是傻瓜式进行分类讨论,分类的情况很细很琐碎,导致复杂度高。

3.2.2 思考可以通过怎样的方式来降低方法的复杂度

        应该进一步优化分类讨论,将可以合并的情况和在一起写,尽量控制if嵌套的情况出现。

        同时,在每个分支中部分的实现代码基本一致,但是我没有提取。为了降低复杂度,我应该提取相同的方法,提高代码可读性、可维护性。

3.2.3 思考与总结

        在强测与互测出现的低级错误归根结底还是自己对题目的思考不够,测试的覆盖面不够,过于依赖评测机测试。

        对于一些细节,例如前导零的处理、指数的类型等,容易想当然,不进一步思考可能出现的问题,自认为不会出现某些情况,没有实际构造数据去验证。对于求导错误,还是因为写完没有再次检查,在测评机上跑了几趟就以为没有任何问题了,特别是第三次作业相比前两次作业较容易,写完就放那里不进行更细心的检查,导致疏忽。

        在接下来的单元测试中,我应该更加细心,深刻理解题意,不只是停于表面。

4 分析自己发现别人程序bug所采用的策略

        主要是利用同学的测评机发现Bug,对测评数据进行化简,找到出错的点。按照这个方法,成功对互测屋成员进行了几次hack。

        值得反思的是,我在几次的互测中,并没有仔细阅读被测程序的代码设计结构,也是过于依赖评测机,所以在接下来的几次作业中,要认真对待互测。

5 分析自己进行的优化

        权衡了优化的代价与正确性,这三次作业我选择不对结果进行优化。

6 心得体会

        记得开学第一天就布置了第一次作业,有一种和寒假突然割裂的痛感。那天晚上包括第二天,都对思路、架构毫无想法,在网上找往届的博客,和同学讨论、看公众号……但是在这一个过程中,我依然是毫无头绪,最后终于在周三的下午,我在纸上整理了自己的思路,生成了最初的架构。在忙忙碌碌却毫无头绪中,我非常挣扎,一度觉得自己第一次作业就交不上去,但最终生成初版的代码,能够浅浅运行,感觉整个人都松了一口气。

        第二次作业最基本的新增代码很快写出来,但是接下来就是漫长的debug过程,在本次作业,对于深克隆还有改写equal方法出现的问题,我经过很久的测评才发现问题。这一周的工作量很大,在这里非常感谢舍友们的帮助!!

        第三次作业相比于前两次作业看起来是比较简单的,但是,我粗心的毛病又犯了,在Mono类的求导求错了,罪魁祸首是一个分支内的一个系数写错了,直接导致本次强测50+,甚至没有进互测屋。反思过来,就是太依赖测评机了,自以为跑了十几二十次测评机没有出现问题就是完全正确了,没有对求导步骤进行更加精细的检查。同样也说明了分支过多导致测评不完全,所以在接下来的作业中,我要简化分支,尽量不写if嵌套,写完一定要自行进行检查,不过度依赖测评机。

        总的来说经过三周oo作业的洗礼,我认识到设计的重要性,全面的设计让我们编写代码的过程中思路更加清晰;认识到架构的重要性,良好的架构有利于多次的迭代;认识到测试的重要性,尽量要覆盖代码的每一个分支。同时,最重要的是,我要从之前面向过程的思维转变为面向对象的思维,关注类之间的内聚与耦合。

        在接下来的作业中,我要注重测试,确保不发生这三次作业同样的低级错误,深刻理解指导书,思考特殊、极端的情况。

7 未来方向

        对我个人而言,我感觉第一次作业布置后的压力非常大,特别是毫无头绪的那些天,我觉得可以在oo课上或者指导书上多讲一些相关知识或者提供一些方向,让我们梯度过渡、适应、完成作业。

  • 15
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值