前言

  本次博客是针对面向对象的前三次作业中出现的问题进行的反思与思考。由于大一学习的程序设计与数据结构属于比较基础的课程,且使用C语言实现,在做题过程中总是采用面向过程的方法,使得程序冗长,一main到底。而本学期的前三次作业虽然强调面向对象,但由于理解深刻,往往无法实现真正意义上的高内聚,低耦合,在程序架构,封装性,复杂度方面均出现或多或少的问题。

基于量度分析程序结构

  为了用更加量化的数值来体现自己代码有多烂,使用IDEA中的Metrics Reloaded插件来做一些更深入的分析。首先对插件中复杂性测试中的部分指标进行说明:

  复杂度指标:

  •  循环复杂性  v(G)

       穷尽程序每一条路径所需要的实验次数。对于类,有OCavg与WMC两个项目,分别代表类的方法的平均循环复杂度和总循环复杂度。

  • 基本复杂性 ev(G)

       方法的结构化程度。范围在[1,V(G)]之间,值越大则程序的结构越病态,其计算过程与图的“缩点”有关。

  • 方法扩展的循环依懒性 iv(G)

         方法与它调用的其他方法的紧密程度。范围在[1,V(G)]之间,值越大则其与其他方法之间联系越紧密

  依赖度指标:

  •   Cyclic

      和类直接或间接相互依赖的类的数量。这样的相互依赖容易导致代码可读性较差,调试困难

  • Dcy和Dcy*

      计算了该类直接依赖的类的数量,*代表包括了间接依赖的类

  •   Dpt和Dpt*

      计算了直接依赖该类的类的数量,*代表包括了间接依赖的类

  第一次作业

  第一次作业的类图如下:

  

                                             程序结构复杂度如图:

  

  第一次作业由于限制条件较少,且没有想到之后的扩展问题,采用一个正则表达式直接匹配整个表达式的方法。而表达式类的构造函数将字符串处理的工作一并揽下,而没有使用“抽象工厂”的模式。而对面向对象的思想也没有多少领悟,所以把读入,求导,简化,输出当做四个函数来写....而当时没有采用返回一个新Expression类,而是直接在原类上进行修改,在这次作业中后果未体现,不过在第三次作业中尝到恶果。

  第二次作业

  第二次作业的类图如下:

  

  

  程序结构的复杂度如图:

  本次将幂函数和三角函数分别定义类,并实现了他们的求导和输出方法。按照UML类图可看出,Exp和Tri基本上符合继承的条件,但由于对继承思想的不了解,将其分为两个类,没有实现上层的统一性。而Key类作为HashMap中的Key,代表着该项幂函数指数,正弦函数指数和余弦函数指数,其中重构了必需的equals方法和hashCode方法。而复杂度表只显示了三项数值均不为1的函数,其中getStringtoPrint使用了太多的if语句来实现系数为+1,-1,指数为+1等情况的化简,导致v(G)偏大;而toSimply方法使用两个for循环来将指数相同的项合并,导致基本复杂性过大;而toStandard用于识别不同类型的因子,也采用了较多if结构,导致整体复杂度较大。

  第三次作业

  第三次作业的类图如下(捂脸):

  

  程序结构的复杂度如图:

  

  在第三次作业中,原本按照指导书中的提示构造出了接口——抽象类——因子与运算规则的三层结构,之后建立了表达式树结构。然后由于前期构思花费了大量的时间,导致后来构建输入处理的状态机时遇到问题没有足够的时间进行处理(没有想到之后座谈课上讲述的三层状态机结构),且表达式树的构造存在诸多细节,如:a*b+c此类结构需要将+c放在a*b的*结点上方;嵌套规则的lchild中应有指针指向rchild;在求导过程中如何使用clone方法在不破坏树的结构的前提下构造出新的求导之后的树。在匆忙之下,完成了以上病态的面向对象代码,对此无语置评,只能怪自己对数据结构不够熟悉,对面向对象框架的实现不够了解。此次作业几乎完全面向过程,在一天时间内完成,而在之后的Apply Creation Pattern环节将会把构思好的框架给出。

自己程序的bug

  • 第一次作业中,强测没有将正项提前,得分99+;互测过程中,没有考虑\s中包括的\v和\f,被找出的均为此同质bug。
  • 第二次作业中,强测仅使用了最简单的sin(x)^2+cos(x)^2=1的化简规则,得分93+;互测过程中,没有被找到bug。
  • 第三次作业中,强测由于没有化简,且没有考虑到结尾存在*这一点,得分90+;互测过程中,没有被找到bug

测试他人程序bug方法

  测试他人程序时总共采取了三种方式:

  •   认真理解他人代码,并找到他人代码的bug

     优点:1.认真读取优秀的代码往往能够让自己学到很多东西,从更加精简的语法到更加科学的架构,有时候读下来感觉受益良多,甚至能在读取过程中同时找到自己的bug;

        2.真正通过从字里行间分析代码漏洞可以让自己的思维更加缜密,在提升debug能力的同时提高自己提前测出自己bug的能力。

        缺点:1.并不是每一份代码都值得细细欣赏,部分同学的代码无条理,无注释,无README,此类三无代码根本无法令人有读取的欲望;

         2.无条理的代码令人疑惑不解,导致程序中的错误反而被放过。有时候读完一长串枯燥无味的代码却“掩卷茫然”,一无所获是多么失望的一件事。

  •   半自动化构造自己能想到的所有易错样例,一次测试ROOM中所有成员的代码

     优点:1.能够以比较快的速度找到尽可能多的bug,同时在测试前通过对代码整体的重新审视,有可能发现自己原本没有考虑过的情况;

        2.可以在bug找到之初便确定bug的原因,不会出现怀疑是否为同质bug而不敢提交的情况。

     缺点:1.仅仅能够找到自己已经想到而别人没有发现的bug,而不是根据他人代码中的漏洞来设计测试用例

  •   使用自动化工具构造样例,一次测试ROOM中所有成员的代码

     优点:1.无脑式操作,将脚本编好之后直接后台测试数据,最后人工筛取部分样例进行提交;

        2.简单高效,在很短的时间内可以将整个ROOM中所有人的常见bug全部测试出来,奖励分++++。

     缺点:1.无知识收获,仅锻炼了写Shell/Python脚本能力,而没有真正获取到他人代码中的精髓之处;

        2.无成就感,找到的bug甚至不能确切知道它错在哪里,在提交还是不提交的纠结中度过debug时间(是否提交的是同质bug)。

Applying Creation Pattern

  第一次作业

    第一次作业中代码基本还是面向过程的,复用性不尽人意。将Factor单独归类,然后用Poly类中采用ArrayList或Hashmap进行连接可以最大限度提高复用性。

   第二次作业

    第二次作业中除了toString方法基本上没有复用之前代码。此次为了化简方便,放弃了ArrayList而重新写了Hashmap进行存储。将因子分成三角函数类和幂函数类,并实现了求导方法,重载了toString方法。

   第三次作业

    在完成过程中复用了幂函数类和三角函数类的求导和toString方法,在三角函数类中加入底数(base),并将其设为ArrayList<trem>,使用嵌套链表的形式进行存储。

    在作业中采用Expression存Terms,Terms存Factor类的方法,而之后感觉与指导书上说明的tips方法不符,我将设想的另一种框架同时在下方列出。

    重新思考后的求导接口统一化规范:

  

  该框架为第三次作业构思时搭建而出的,建立Factor和Method两个抽象类。将三角函数中的Sin和Cos都归类到Sines类中,用type属性进行区别;将幂函数和常数归类到Factor类中,将常数视为指数为0的幂函数。而运算规则类中包含四个具体的运算规则,包括Add,Sub,Mult,Nest:

 1 public abstract class Method implements der {
 2
 3     private der parent;
 4     private der lchild;
 5     private der rchild;
 6
 7     public Method() {
 8         lchild = null;
 9         rchild = null;
10     }
11
12     public der getLchild() {
13         return lchild;
14     }
15
16     public void setLchild(der lchild) {
17         this.lchild = lchild;
18     }
19
20     public der getRchild() {
21         return rchild;
22     }
23
24     public void setRchild(der rchild) {
25         this.rchild = rchild;
26     }
27
28     public der getParent() {
29         return parent;
30     }
31
32     public void setParent(der parent) {
33         this.parent = parent;
34     }
35
36     public Method(der lchild, der rchild) {
37         this.parent = null;
38         this.lchild = lchild;
39         this.rchild = rchild;
40     }
41
42     public abstract der derivation();
43
44 }

 1 public class Add extends Method {
 2
 3
 4     public Add(der lchild, der rchild) {
 5         super(lchild, rchild);
 6     }
 7
 8     public der derivation() {
 9         der temp = new Add(super.getLchild().derivation(),
10                 super.getRchild().derivation()
11         );
12         return temp;
13     }
14 }

 1 public class Sub extends Method {
 2
 3     public Sub(der lchild, der rchild) {
 4         super(lchild, rchild);
 5     }
 6
 7     public der derivation() {
 8
 9         der temp = new Sub(super.getLchild().derivation(),
10                 super.getRchild().derivation()
11         );
12         return temp;
13     }
14
15 }

 1 public class Mult extends Method {
 2
 3
 4     public Mult(der lchild, der rchild) {
 5         super(lchild, rchild);
 6     }
 7
 8     public der derivation() {
 9         der mult1 = new Mult(super.getLchild().derivation(),
10                 super.getRchild()
11         );
12         der mult2 = new Mult(super.getRchild().derivation(),
13                 super.getLchild()
14         );
15         der add1 = new Add(mult1, mult2);
16         return add1;
17     }
18 }

 1 public class Nest extends Method {
 2
 3
 4
 5     public Nest(der lchild, der rchild) {
 6         super(lchild, rchild);
 7     }
 8
 9     public der derivation() {
10         der mult1 = new Mult(super.getLchild().derivation(),
11                 super.getRchild().derivation()
12         );
13         return mult1;
14     }
15 }

由此建立整个表达式树,将三角函数因子与幂函数因子作为叶子节点,将运算规则方法作为根节点和分支节点:

方法如下所示:

Add/Sub节点:Lchild ->加数  Rchild ->加数

Mult节点:Lchild ->乘数  Rchild ->乘数

Nest节点:  Lchild ->Sines(base) 其中base指向Rchild  Rchild ->嵌套内容的根节点

使用根节点运算规则的求导方法,可直接将整个表达式树进行求导,最后返回一棵新的表达式树。表达式树按照前序遍历的方法可以用getString方法得到最后的输出结果。

对于输入内容的处理,应采用梯度下降的方式,从表达式->项->因子采用三层的小状态机(当时试图采取一层的大型状态机,最后因为同时考虑细节过多而无法完成)。

写在最后

  本几次作业以实践的方式让我们了解到:在创建大型工程/不断升级需求的挑战中,面向过程->面向过程的思维转变是不可或缺的。期待之后的面向对象学习与作业,让我能更加感受到JAVA的魅力所在。

1

转载于:https://www.cnblogs.com/ArthurN/p/10601197.html

面向对象第一单元(表达式求导)总结体会相关推荐

  1. OO_2019_第一单元总结——表达式求导

    一.基于度量的程序结构分析 首先给出Complexity metrics中参数的含义: ev(G):基本复杂度是用来衡量程序非结构化程度的,非结构成分降低了程序的质量,增加了代码的维护难度,使程序难于 ...

  2. 面向对象第一单元总结

    一.对面向对象的理解 有位同学给java的面向对象做了一个形象生动的类比,我觉得很有道理,大概按我的理解如下: 结构的形成 看图之前,我们要先明白,世界上是先有了实体,才有了一步步抽象至以上的体系结构 ...

  3. 面向对象第一单元个人总结

    面向对象第一单元个人总结 这次主要依据作业要求中的四个层次来分析这一个月的学习.从对oo,java一无所知到逐步探索,在作业压力下学习各种知识.现在就是总结的时候了. (1)基于度量来分析自己的程序结 ...

  4. java求导数_OO_JAVA_表达式求导

    OO_JAVA_表达式求导_第一弹 ---------------------------------------------------表达式提取部分 词法分析 ​ 首先,每一个表达式内部都存在不可 ...

  5. oo第一次博客-三次表达式求导的总结与反思

    一.问题回顾与基本设计思路 三次作业依次是多项式表达式求导,多项式.三角函数混合求导,基于三角函数和多项式的嵌套表达式求导. 第一次作业想法很简单,根据指导书,我们可以发现表达式是由各个项与项之间的运 ...

  6. Mathematica对函数表达式求导并设置为新的自定义函数

    自定义函数 自定义函数需要注意亮点 1.最好使用 := 而非 = 2.定义时等式左端函数变量有下划线,被称为"空白" Wolfram 系统变换规则最强有力的方面或许是它们不仅能用于 ...

  7. BUAA_OO第一单元总结性博客作业——表达式求导

    一.程序设计思路 在我的三次作业中都采用了类的分层结构,采用逐项匹配,分层求导的思路. (一). 第一次作业中构建了Polynimial(多项式)类,在类的构造器中就完成了对非法空格的判断并对合法表达 ...

  8. oo面向对象第一单元总结

    oo第一次作业主要考察了多项式的求导,从简单的幂函数求导到三角函数求导再到嵌套函数的求导,难度循序渐进,对我们对于面向对象的理解的要求也在一次一次提升.一行行代码打下来,一夜夜熬过去,我也来到了这个短 ...

  9. java求导数_JAVA实现表达式求导运算的分析总结

    1第一次作业 1.1题目描述 对形如4*x+x^2+x的多项式求导. 1.2类图 1.3度量分析 在完成第一次作业时,我的写法没有特别的"面向对象".唯一封装起来的是Node,代表 ...

  10. 数学第一单元计算机思维导图,三年级数学上册第一单元思维导图

    <三年级数学上册第一单元思维导图>由会员分享,可在线阅读,更多相关<三年级数学上册第一单元思维导图(4页珍藏版)>请在人人文库网上搜索. 1.重量单位的认识: l 我们通常所说 ...

最新文章

  1. 客快物流大数据项目(四):大数据项目为什么使用Docker
  2. Solr初始化源码分析-Solr初始化与启动
  3. Des和Base64的Util
  4. silverlight 跨域文件位置
  5. 实验三:xen环境下的第一个虚拟机的安装
  6. idea(三)最值得安装的几款插件
  7. 巧妙利用channel进行golang并发式爬虫
  8. Elasticsearch整理笔记(五)
  9. Python——迭代器的几个高级用法
  10. 如何看待阿里云加入Linux基金会金牌会员?
  11. Docker:设置容器自动启动
  12. UVa 10870 - Recurrences 矩阵快速幂
  13. AI 之 OpenCvSharp 安卓手机摄像头识别人脸
  14. VHDL:基于 FPGA 实时处理的双目测距系统
  15. 计算机c盘要满了电脑会卡吗,电脑卡就一定是C盘装太满吗?
  16. 从零开始学统计 03 | 均值,方差,标准差
  17. C++调用Matlab生成的DLL动态链接库进行混合编程(win10+VS2015+Matlab2016b)
  18. 外文版计算机科学期刊,EI(SCI) 收录国外英文期刊(计算机类)
  19. 咋阻止别人用计算机监控我家,我想用我家里的电脑控制办公室电脑的打印机怎么处理?...
  20. UE4贴图自适应屏幕大小

热门文章

  1. 从openjdk.java.net获取OpenJDK8源码并编译(amd64/aarch64/arm64)
  2. 恶意混时间你不敢管,却要吓唬全体员工?
  3. JAVA NP插件,特定的宽度600,插件就不显示
  4. cygwin终端中显示的中文改成英文(没成功)
  5. 为了USB3,吾还是换了电脑
  6. 全网首发:以字型为例,一维表示的二维数组矩阵,以易理解的方式旋转90、-90
  7. 2002-11-17梦笔记
  8. JAVA命令行运行时设置参数
  9. OpenJDK8和OpenJDK8u的差异
  10. 现在一行代码允许长度,80太少,120才算正常