OO第一单元总结

OO第一次单元总结

​ 前三次的OO做业的内容总的来讲都是围绕着多项式求导,从最简单的x的幂函数的求导逐渐增长难度,最后完成含有三角函数和嵌套因子的多项式求导。可是在这三次的程序编写和debug中,我也出现了大大小小的问题,因此在此,我对于OO前三次做业的完成作一个总结,使本身对于存在的问题可以认识得更加清晰。java


第一次做业

(1)整体归纳

  • 题目要求正则表达式

    简单多项式求导,多项式的每一项中只含常数和x的幂函数。编程

  • 思路数组

    在第一次做业中,多项式的构造比较简单,因此在这个时候为了更加直观、方便,我选择了正则表达式做为主要的工具对于多项式的每一项进行获取(这也为第三次做业遇到的困难埋下了伏笔),具体的正则表达式以下模块化

    (第一项符号比较特殊,单独判断)函数

    第一项的正则表达式:工具

Pattern p0 = Pattern.compile(
                "([+-]?[ \\t]*)([+-]?)(\\d*)([ \\t]*[*]?)" +
                  "([ \\t]*x?)" + 
                  "((?:[ \\t]*\\^[ \\t]*[+-]?\\d+)?)");
        Matcher m0 = p0.matcher(str);

​ 其余各项的正则表达式:学习

Pattern p1 = Pattern.compile(
                "([+-][ \\t]*)([+-]?)(\\d*)([ \\t]*[*]?)" +
                        "([ \\t]*x?)" + 
                    "((?:[ \\t]*\\^[ \\t]*[+-]?\\d+)?)");
        Matcher m1 = p1.matcher(str);

​ (以上正则表达式中存在对于空格的判断问题,在bug分析部分将会具体分析)测试

​ 在分离出每一项以后,开始进行常规的求导得到每一项求导后的系数和幂指数,最后将这些结果存入一个ArrayList中(同时进行合并同类项),最后进行输出。优化

  • 优化

    由于此次做业中只包括常数项和x的幂指数项,因此在优化上主要进行了常数项的合并以及幂指数相同的项系数的合并。

(2)基于度量分析程序结构

  • 整体结构介绍

    因为第一次做业须要完成的实现比较简单,而且在OO学习的开始面向对象的思想尚未创建起来,因此在第一次做业中我主要仍是按照计算过程建了四个类,分别进行每一项的提取、求导、计算长度,以及结果的输出。

  • 类图

    从类图中能够看出,程序主要仍是以面向过程的开发为主,而且没有更具体细化每个类的功能。

  • 主要度量图

    由度量图能够看出,在代码中的一些方法中,ev(G)和v(G)的值过大,说明这些方法的非结构化程度较高、独立路径过多,这也为代码以后的维护带来了困难。除此以外,代码中的类的WMC值广泛偏高,PolyDiff类的Ocavg值也偏高,这也代表着代码的复杂度太高,代码在设计上存在很多不合理的地方。

(3)bug分析

  • 本身出现的bug

    在第一次做业中,个人程序所有栽在了空格的识别上。

    1. 没有正确理解指导书的含义,没有在识别空格时将除<space>\t的空格判断出来;
    2. 在其中一处正则表达式中忘记加入\\s*.

    其实上述的错误都是一些因为理解或粗心而形成的错误,这也充分体现出了我在写代码时对于寻找本身的bug过于忽视,想固然地认为程序已经达到本身的预期效果。须要警醒!!!

  • 他人的bug——以此为戒

    因为第一次的做业比较简单,因此你们的bug都属于比较粗心的错误(好比容许指数中负号与数字间有空格),主要引起这些错误的缘由仍是由于对于指导书的理解不足。这也体现出了理解题意的重要性,而且在写程序前也应该先预计好可能引起bug的数据从而更好地避开这些致命的小bug。


第二次做业

(1)整体归纳
  • 题目要求

    对于含有常数、x的幂函数、sin(x)的幂函数、cos(x)的幂函数的多项式进行求导。

  • 思路

    因为第二次做业的因子只有固定、较为规则的四种类型,因此我在最开始读入多项式时将全部的项分为了四个部分,并运用了一个数组存入每一个项分别的整个项的系数、x的指数、sin(x)的指数、cos(x)的指数(这也使第三次做业须要从新进行构造)。接着经过求导的公式,对于每一项进行求导,最终获得一个ArrayList并将其输出。

    下面是正则表达式的格式(此时已经去掉了表达式中的空格)(因为排版问题,正则表达式的格式可能出现问题):

    String teststr1 = "[+-](?:(?:[+-]?[+-]?\\d+)|(?:                       [+-]?" +
                    "(?:(?:sin\\(x\\))|(?:cos\\(x\\))|x)                       (?:\\^[+-]?\\d+)?))";
    String teststr2 = "\\*(?:(?:[+-]?\\d+)|" +
                    "(?:(?:(?:sin\\(x\\))|(?:cos\\                     (x\\))|x)(?:\\^[+-]?\\d+)?))";
    String teststr = teststr1 + "(?:" + teststr2 + ")" +               "*";
    Pattern p = Pattern.compile(teststr);
    Matcher m = p.matcher(str);
  • 优化

    值得注意的是,此次做业中的sin(x)和cos(x)的格式都很是固定,因此还能够对于$sin(x)^2+cos(x)^2=1$进行化简。在此个人化简策略是在将每一项求导结果加入最终的list的时候就经过查找将符合$sin(x)^2+cos(x)^2=1$的输出项合并,所得新的项在此进行list的插入操做,运用一个递归将最终输出的内容尽量化为最简。

(2)基于度量分析程序结构

  • 整体结构介绍

    在本次做业中,我创建了五个类,分别进行输入、输出、提取项、提取因子、对于因子进行求导等操做。可是能够看出,在编程思想上此次做业仍是受到了不少面向过程的思想,而且程序的复用性极差。

  • 类图

    在本次做业中总共创建了5个类,可是每一个类的功能仍是不够具体,这也致使在下一次做业中没法对于这些类进行沿用。

  • 主要度量图

    由此次做业的度量图中能够看出方法PrintPart和InsertList的复杂度都太高,这也与其内部带有递归相关。同时对于类的复杂度,能够明显地看到DealWithPoly类的复杂度太高,这也是因为在DealWithPoly类中进行输出时运用过多判断语句,使代码过于冗长。

(3)bug分析

  • 本身的bug

    在第二次做业中总共出现了两个bug:

    1. 第一个bug为输出格式错误,错误在输出中换行了,主要为粗心和测试不全面而产生的问题;
    2. 第二个bug因为沿用了第一次的求导方法而产生的错误:在第一次做业中,因为最终结果不会出现x^-1,因此在输出中我直接将x^-1做为0输出,这种方法在第一次做业的处理中当然简便,然而对于第二次做业倒是致命的,由于在第二次做业的结果中会存在x^-1,然而这样的操做却忽视了全部含有x^-1的输出项。
  • 他人的bug

    此次互测中我发现的他人的bug只要仍是格式判断的错误,其缘由仍是没有对于指导书中的格式要求考虑全面。


第三次做业

(1)整体归纳

  • 题目要求

    此次做业的主要要求还是进行多项式求导,主要的求导部分还是常数、x的幂函数、三角函数的幂函数。可是不一样之处在于在此次做业中加入了嵌套因子以及表达式因子,表达式的读取方式需变为一种递归处理。

  • 思路

    刚开始拿到题目时,本身一直在思索应该怎么运用正则表达式来表示出表达式的形式从而判断表达式的格式是否正确,可是苦苦思索无果(java的正则表达式中没法进行递归,且运用正则表达式定会爆栈)。最终,经过理解指导书中推荐方法以及讨论区大佬们对题目的理解,我决定放弃掉在前两次做业中均使用到的长正则表达式,决定使用其余的方式来判断表达式格式是否正确,如判断括号、在局部运用小正则进行特殊格式判断。

    判断格式是否错误的正则表达式举例:

    Pattern p = Pattern.compile("\\*[\\+-]+(?:x|s|c)");
    Matcher m = p.matcher(str);
    
    Pattern p1 = Pattern.compile("\\*[\\+-]{2,}\\d+");
    Matcher m1 = p1.matcher(str);
    
    Pattern p2 = Pattern.compile("\\^[\\+-]{2,}\\d+");
    Matcher m2 = p2.matcher(str);
    
    Pattern p3 = Pattern.compile("[\\+-]{4,}\\d+");
    Matcher m3 = p3.matcher(str);
    
    Pattern p4 = Pattern.compile("[\\+-]{3,}(?:x|s|c)");
    Matcher m4 = p4.matcher(str);
    
    Pattern p5 = Pattern.compile("sin\\([\\+-]{2,}\\d+");
    Matcher m5 = p5.matcher(str);
    
    Pattern p6 = Pattern.compile("cos\\([\\+-]{2,}\\d+");
    Matcher m6 = p6.matcher(str);

    在初步判断表达式的格式后,我经过+-将表达式分割为项,以后再经过*将每一项分为符合指导书要求的因子。以后再求导操做中,我按照指导书中的因子类型,将须要求导的因子分为<u>常数型</u>、<u>x的幂函数型</u><u>多项式因子型</u><u>sin(factor)的幂函数型</u>、<u>cos(factor)的幂函数型</u>,并为其创建各自的类,其中因为sin和cos的括号内部能够做为一个因子,因此咱们能够再次调用因子求导的类,判断其中的因子是否知足格式要求并进行求导。

  • 优化

    在第三次做业中,因为我为了方便而在输出的list中没有将每项的系数和幂指数进行分开而是将每一项做为一个系数和字符串的结合体,因此这也使我在想要进行优化时带来了麻烦。可是考虑到本次做业除了常数项可以合并的同类项并非不少,其实在进行优化时咱们只考虑常数项的合并,并将能去掉的括号不进行输出,也可以取得不错的优化效果。

(2)基于度量分析程序结构

  • 整体结构介绍

    在本次做业中,面向对象的思想终于稍微出现。在做业代码中,总共有10个类,其中除了输入输出、获取因子和项以外,还创设了对于各类因子不一样的求导类。

    可是,在本次做业中,我忘记使用继承及接口(说到底仍是没能理解继承和接口的精髓),致使不少类似的类中的类似代码屡次出现,而且没有对于类似的类规定统一的接口。

  • 类图

    分析类图,能够清晰的看出,在程序中有许多类似的类没能进行程序代码和接口的统一。

  • 主要度量图

    从方法的度量表中能够看出有关求导后结果的list建立的函数中的代码复杂度太高,方法难以进行模块化、难以进行测试和维护,方法的可复用性不高。这也是因为这些方法中的循环和判断语句使用过多形成的。除此以外,PickUpTerm类和PickUpFactor类也过于复杂,对于这些类,复杂度太高的主要缘由主要仍是运用了面向过程的方法,没有能很好的将它们的功能进行分割。

(3)bug分析

  • 本身的bug

    在此次做业中,因为在写代码时没有可以保持一个比较清醒的态度,代码也没有很好的模块化,致使有些前面考虑到的状况在后面写相关的代码时忘记了。体如今代码上即是,在进行表达式因子的读取时,没有考虑前面符号(其实在前面的代码中已经对于符号进行了判断)。因为这一行的错误致使强测和互测被刀到肉疼!

    这也提醒我在写代码时必定先进行完备的考虑后再进行代码编写,而且在测试时也不能仅仅依靠现有的测试数据,要尽量寻找可能出现的错误,并将其进行组合。

  • 他人的bug

    因为此次不容许wf数据的测试,让一些同窗逃过了一劫,可是从我找到的错误来看,你们主要仍是格式的判断的失误(像我这样因为求导过程的错误实在很少/(ㄒoㄒ)/~~)。主要的错误有:在三角函数中没能正确判断因子格式、在乘法中错误判断格式(主要都出如今常数项的符号判断上)。

<u>(4)寻找他人bug的策略</u>

就着第三次做业我来谈一谈本身在寻找bug时的策略:

  • 总体来看,我在前两次做业中的hack策略为“黑盒测试”和“白盒测试”相结合:
  1. 黑盒测试:主要针对于格式的错误,好比wf的误判等。可是因为在前两次做业中格式的要求比较简单,因此这种测试的效率其实也不算很高,主要在因而否能构造出比诡异奇特、容易考虑不到的测试点。
  2. 白盒测试:在前两次做业中,代码量还算比较小,因此进行白盒测试仍是有必定的可行性的。可是要想真正完成看完每一个人的代码仍是不现实的。因此在进行白盒测试时,我主要着眼于空格等格式的判断以及正则表达式的构造、还有输出时符号的判断等。
  • 在第三次做业中,因为代码量的增长,而且考虑到你们求导的思路有比较类似,求导步骤出错可能性较小,我只进行了对于格式方面的黑盒测试。运用我在写代码是所考虑到的特殊格式对于同组的代码进行测试。结果显示在第三次做业中,你们的错误的确集中在对于wrong format的判断上,黑盒测试在此次hack中效果仍是不错的。

虽然目前为止,我经过现有的方法找到了很多bug,可是相比同组大佬仍是相差甚远,因此我也须要在从此的debug之路上更进一步,能够对于程序产生随机数据上进行探索~~(虽然我以为经过思考构造数据可能找到bug的效率更高)~~。


Applying Creational Pattern

在本次实验中,因为咱们的求导操做经过因子的类型区分为不一样的过程,可是总的来讲都是在进行求导这一操做,因此咱们能够选择使用工厂模式

**工厂模式:**工厂模式是一种实例化对象模式,是用工厂方法代替new操做的一种模式。具体操做主要为创建一个工厂类,对实现了同一接口的一些类进行实例的建立。

重构具体方法:

  • 首先咱们先决定将哪些类放入一个工厂中——对因子求导的类。
  • 以后先使这些类继承一个接口。
  • 创建一个工厂,并经过判断条件决定在工厂中调用哪个类。
  • 即可创造出咱们所须要的类。同时系统的可扩展性也大大提升。

总结

回顾完成这三次做业的过程,能够明显感觉到本身在这一阶段的进步----从一个java小白到如今能够较为熟练地运用java的基本语法,而且对于面向对象编程有了初步的了解和实践。可是不能否认,本身目前仍是一个小菜鸡,在程序的构造和debug的能力上有着很大的欠缺,编程的思路也常常很不清晰,对java的了解也不深刻。

在接下来的学习中,我也须要有所针对,要不只能学其所用,更能用其所学。

相关文章
相关标签/搜索