前言:

这是一篇面向对象作业总结,作业内容是对多项式进行求导,一共有三个阶段,具体要求不详述,第一阶段只要求’+’连接coeff*x^pow的形式,第二次支持*连接的幂函数及三角函数,第三次则需要支持括号表达式的嵌套。本想不用编译原理所述表达式树,最后发现做成一团乱麻。

第一次作业

类图如下:

说明:第一次作业比较简易,主要是对新版eclipse和checkstyle的安装和熟悉。词法分析器为Token,可以考虑将其单例化,因为只有一个词法分析器。用Poly存储多项式的系数和幂次,在PolyDif里有着主入口,根据加号拆项,以HashMap<>存入<幂次,系数>,按求导法则进行求导,最终遍历Map以输出结果。

代码度量结果如下:

Bug:不能直接去除所有空格,因为+ 10不算数字。

0不输出,由于大整数0输出时前面没有+,导致我强测三处没过,改正方法就是判断系数是否为0,是则跳过。

还有其他,总的来说,bug存在于词法分析程序以及输出程序,因为其分支比较多。

第一次作业略述如上。

第二次作业

类图如下:

三个Minizer可以不用看,因为不支持括号表达式,所以提取公因式无效

第二次作业也没有什么优化,仅仅是系数合并。构造了一个CompTerm的类,表面一个项由系数、幂次、sin幂次、cos幂次所唯一决定,这种断言有局限性,不宜扩展,但是可以有效合并系数。

Bug: 由于多处抛出异常,所以导致最后异常没有处理,就是没有输出wrong format,但是打印函数堆栈。最终把所有异常都交给了主入口main。

度量结果如下:

这里有一个静态属性,但是不是词法分析程序,他是scanner。而词法分析器被分给了diff主控程序,就是语法分析器,这样造成的问题在第三次作业中有所体现。总之,这个类关系勉强可以应对现有需求。

第三次作业

第三次作业的类构造是有问题的,类图如下:

这个类关系图甚至比上一次还要少了,其中Diff本来是对表达式进行语法分析的一个类,它内嵌了一个词法分析器,还有两个字符串,一个是输入的表达式,一个是求导后的表达式。而对因子和项进行分析的函数调用了专门负责求导的函数。作为结果,对项和因子进行分析的两个函数getTerm和getFactor,都是用两个字符串作为返回值的,一个意味着分析到了什么样的串,一个是求导后的结果。然而我直接用Diff类本身作为其中方法getTerm和getFactor的返回值,让Diff类的功能比较模糊。Sin和cos又继承了Diff类,意味着创造它们的实例就可以得到Sin(…)和其求导结果。然而这样做使得词法分析器进行了复制和分裂,就不再是全局的词法分析器了,这样一方面占用额外内存,还会导致各个词法分析器处理到的位置是不同步的,这里有很多bug,而这样仅仅是让Sin可以独立分析其自身表达式。最后在优化时,由于Diff功能太过耦合,所以Optm不能再继承Diff,而是另外完成了一个语法分析器,代码多有类似。

问题的本质就是不想用全局变量,可以说所有类的实例都是临时开的,然后通过字符串进行互相传递,没有抽象出表达式树。可以开两个静态变量,就是词法分析器和表达式树的根节点,而不是完全依赖与语言递归的特性进行字符串处理。

度量结果如下:

可以看出,代码规模并不比第二次大多少,这是因为删了第二次中的许多额外功能。

圈复杂度还是过高,3.171,就是分支数太多,这不oo,按照树的方式重构,然后节点实现统一的接口,也许可以降圈复杂度。方法数有72个,这是因为里面大量的都是get和set方法,不能有protected就只能这样进行同步。静态方法还可以再减少,因为那3个方法只是给main用的。Static方法不是不能用,单例模式就要用,但是也不能专门造一个类把所有的方法都设置成static的了,这是底线。想尽量减少static,就发现所有容器都是函数里的临时变量。Static还是要适中。

Bug: 由于用的是字符串进行传递,所以老是会出现括号存去问题。对于(++sin(x))这样的,去括号后是++sin(x),逐层求导后发现是++cos(x),返回时又要去括号,则会出现…*++cos(x)这样的错误串。解决方案是写了个while去掉前导符号。

还有一些bug诸如词法分析器同步时尾部空格数不一样导致偏移值不同,这种bug太细节了,就不多赘述了。

这些bug产生的规律都是由于字符串没有抽象成语法树所造成的。

设计模式

可以考虑工厂模式,因为每次创造Diff或Sin或Cos或Poly或Optm的时候,都只是为其词法分析器赋值,没有牵涉到求导的情况。又不好把求导直接写进构造器,所以可以用工厂方法,制造一个工厂,产生实例的同时执行其特征操作。工厂应当使用静态方法。

总结

还是不能直接把字符串作为内部表示。内部数据的管理应当抽象出来。

oo第一次作业的更多相关文章

  1. OO第一次作业总结

    OO第一次学习总结 1.第一次作业:多项式加法 从未接触过java的我,在从输入输出开始学了几天后,按照C语言的思路,写出了一个与面向过程极其接近的程序. 在这个程序中,存在两个类:一个是Comput ...

  2. 从入门到不放弃——OO第一次作业总结

    写在最前面: 我是一个这学期之前从未接触过java的小白,对面向对象的理解可能也只是停留在大一python讲过几节课的面向对象.幸运的是,可能由于前三次作业难度还是较低,并未给我造成太大的困难,接下来 ...

  3. OO第一次博客作业

    OO第一次博客作业 一.三次作业的bug反省 1.自己发现别人的问题 (1)输入处理的问题,比如第一次作业,主要就是处理输入的字符串,然后有同学的正则表达式有问题,则对于一些错误输入就不能正确判断. ...

  4. OO第一次博客作业--第一单元总结

    OO第一单元总结 面向对象设计与构造的第一单元,对“面向对象”的概念还根本不理解不熟悉,只觉得需要“分模块”,但不知道怎么分,分多少模块,怎么根据需要的模块的功能建立类.学习的进度又太慢,根本跟不上出 ...

  5. oo 第一次博客作业

    oo 第一次博客作业 早在大一就听说了oo的各种传奇故事,大二下学期终于也开始了我的oo之旅. 基于度量来分析自己的程序结构 第一次作业 类图分析 耦合度分析 可以看出在第一次作业中,我的耦合度非常高 ...

  6. 2018 OO第一次总结(作业1-3)

    第一次作业1.程序分析 (1)OO度量 (2)类图: (3)分析与评价: 这次作业由于作业整体设计难度不大,因此按照去年暑假上的OO先导课老师讲的设计方法很容易实现一个还不错的面向对象式程序,类与类之 ...

  7. OO第一次总结作业

    第一次OO博客作业 前言 面向对象课程已经经过了4周的时间.前三次作业全部是关于多项式求导的相关内容,内容由易到难,同时我也开始逐渐深入感受学习面向对象的各项特征,逐渐将自己的编程风格从C向真正的面向 ...

  8. OO第一次博客作业总结反思

    使用了masteruml插件来生成类图和metrics插件分析代码 第一次作业 1.UML类图 >在第一次作业中,使用了两个类,代码中有没有使用的变量与函数,为平衡两个类的内容,我将输出函数放在 ...

  9. OO第一次博客作业(第一单元总结)

    Q:菜是绿的,鸡是黄的,那菜鸡是什么颜色的? A:红的,强测全WA了,能不红么. 菜不菜的问题先不说了,认真研究一下这次的题目,以及WA的原因吧. 程序结构简析 三次实验的核心结构都是差不多 第一次的 ...

随机推荐

  1. Java内存溢出异常(上)

    上一篇文章我们讲了JVM运行时数据区域与内存溢出异常,其中对于内存溢出异常这部分将的不够详细,这篇文章将着重讲解Java内存溢出异常的相关知识.如果有没看过上一篇文章的小伙伴们,请点击Java内存区域 ...

  2. 译:Dataiku 白皮书之《在银行和保险行业应用数据科学》

    原文链接:Data Science For Banking & Insurance 如果不能正常访问,请点击备份获取. 在银行和保险行业应用数据科学 互联网巨头和金融技术创业时代的求生和发展 ...

  3. JAVA基础复习与总结<一> 对象与类的概念_内部类_继承与多态

    一.对象与类 类:类是一个模版,它描述了一类对象的行为和状态. class animal { private int color; private int size; public void eat ...

  4. java @Override 报错解决

    有时候Java的Eclipse工程换一台电脑后编译总是@override报错,把@override去掉就好了,但不能从根本上解决问题,因为有时候有@override的地方超级多. 这是jdk的问题,@ ...

  5. 05-Python入门学习-字符串与列表的内置方法

    字符串 一:基本使用 1 用途: 记录描述性的状态,比如人的名字.地址.性别 2 定义方式: 在"",'',"""""" ...

  6. CMake入门

    CMake入门 CMake是一个跨平台的安装编译工具,可以用简单的语句来描述所有平台的安装(编译过程).他能够输出各种各样的makefile或者project文件,能测试编译器所支持的C++特性,类似 ...

  7. 使用php的curl爬去青果教务系统 课表(转)

    1. 分析 首先我们要了解 Http Cookie 的作用(可参考HTTP cookies 详解),简单来说就是维持一个会话,这样我们就能在登陆一个网页后,就能进入这个网页需要登陆的界面. 现在我们需 ...

  8. 网络编程之socketserver以及socket更多方法

    关于socketserver 关于socket的更多方法 服务端套接字函数: s.bind() 绑定(主机,端口号)到套接字 s.listen() 开始tcp监听 s.accept () 被动接受tc ...

  9. Selenium 3----窗口截图+关闭浏览器

    窗口截图 get_screenshot_as_file() 自动化用例是由程序执行的,因此有时候打印的错误信息并不十分明确.如果在脚本执行出错的时候能对当前窗口截图保存,那么通过图片就可以非常直观地看 ...

  10. 干货 | 教你如何监控 Java 线程池运行状态

    之前写过一篇 Java 线程池的使用介绍文章<线程池全面解析>,全面介绍了什么是线程池.线程池核心类.线程池工作流程.线程池分类.拒绝策略.及如何提交与关闭线程池等. 但在实际开发过程中, ...