BUAA_OO_U1

任晓林-23371399 2025-03-20 08:14:03

一、程序架构

类图与架构

hw1

在这里插入图片描述

  • 预处理init,处理多余的符号和空格,保证只会出现最多一个符号

  • 递归下降

    词法分析Lexer,分析出要处理的符号

    语法分析Parser,根据符号分割,分析出Expr,Term,Factor。分成三部分进行处理——parseExpr, parseTerm, parseFactorparseExpr用加号进行处理,进入解析项,parseTerm用乘号进行处理,进入解析因子。

  • 文法层次设置

    表达式主要包含三部分——ExprTermFactor,而Factor又有三种——幂函数,常数因子和表达式因子,我们对他们进行分别建类。其中Expr类中使用ArrayList来容纳该表达式中含有的TermTerm类中使用ArrayList来容纳该项中含有的Factor

  • 表达式展开

    可以发现最后的多项式具有一个统一的形式,我们可以基于这个形式建立一个Unit类,再建立一个PolyPoly类有一个ArrayList容器,用来容纳Unit,此外还有addPoly()mulPoly()powPoly()等方法来实现多项式的运算。最后只需要实现Poly类里的tostring就可以顺利进行展开化简

​ 当然在这个过程中我们还要运用递归下降的方法,自底向上的用toPoly让每一个都变到Poly项

  • 优化

​ hw1涉及到的优化点不是很多,只需要特殊考虑指数系数为0的特殊情况即可。

hw2

在这里插入图片描述

可以看出我的架构没有发生太大的改变,只是增添了新的功能。

  • 三角函数类

    新建了一个sinFactor类和cosFactor类,包含factor:三角函数括号内的因子和exp:三角函数的指数部分

parser类设置parserSinCosFactor()方法,对三角函数括号内的因子进行解析,然后解析该三角函数的指数,解析因子我直接使用了parseExpr方法,可以处理更多的可能性

  • 递推函数

    在处理递推函数时,我选择增加Definer进行处理,FunFactor进行存储

    Definer中我进行了字符串替换,增加递归的替换方法,等待被调用

    parser类设置parserFunFactor()方法,读到f就进入Definer进行替换,最后返回一个字符串,在进行递归下降处理为Expr

  • 表达式展开

    多项式的基本单元发生了变化从ax^b 到现在的 ax^b(sin)^m(cos)^n

  • 优化

​ 在三角函数的化简方面,我尝试重写equal方法,比较是否相等,还写了一个比较是否是相反数的方法,最后如果是cos和sin的偶数次幂,我就比较它是否equal或者反向equal,如果是sin的奇数次幂,我比较他是否是equal的。以上的优化并未对我的正确性产生什么影响。因为该实现方法并没有对总体的架构产生影响,也不容易产生一些错误。

以上是基本架构,在后期修bug和优化代码时,我试了另外两种种递归函数的方法。第二种方法里不需要对字符串进行过分的解析。只需要替换掉递推函数的序号,然后返回递推函数替换掉序号的字符串,再次进行递归下降。在第三种方法下,有递推函数,先把f0到f5解析出来,之后再遇到f就可以直接替换就可以。不过三种方法最后的性能差距不大。

hw3

在这里插入图片描述

  • 求导

Parser类中增加parseDerFactor方法,parseFactor中调用

然后仍然采用递归下降的思路,层层求导,Expr实现加法,Term中实现乘法法则和链式法则

  • 自定义普通函数

新建了一个工具类NomalFunDefiner对于自定义普通函数进行处理,思路其实和f{0}很相似

parser类中设置了一个parseNormalFun()方法,先解析函数名,然后解析所有的实参

OO度量

在这里插入图片描述

在这里插入图片描述

仅展现出数值高的部分

  • 每个方法的规模与控制分支数目

    • 规模:通过 v(G)(圈复杂度)间接评估,数值越高逻辑越复杂。
      • 高复杂度方法:
        • Definer.calFunc(FunFacter)(v(G)=8)
        • Unit.sinCosEqualHash(...)(v(G)=20)
        • Poly.mulPoly(Poly)(v(G)=13)
    • 控制分支数目:v(G) 直接反映分支数目。
      • v(G)=20 表示可能存在嵌套循环或大量条件分支。
  • 类的总代码规模

通过 WMC(加权方法复杂度)体现:

  • 高规模类:
    • Poly(WMC=53)
    • Unit(WMC=50)
    • Definer(WMC=29)
  • 低规模类:
    • Number(WMC=5)
    • Var(WMC=5)
  • 内聚性
  • OCavg(平均操作复杂度):

    • 低值(如 1.00)表示高内聚(如 NumberVar)。
    • 高值(如 Poly.OCavg=4.42)表明类职责分散,内聚性较低。
  • 耦合性

    • 隐式耦合
      • DefinerFunFacter 交互(方法参数)。
    • 高耦合类:
      • PolyUnit(涉及复杂数据操作,如 addPolymulPoly)。

优点

就架构而言,我的思路是很清晰的,也具有很好的拓展性,可以继续加很多东西。

可能的迭代方向

比如加一些指对函数,一些定义函数,连续求积,连续求和等。

按照我的架构而言,仅仅只需要在其中加入因子,修改一些计算逻辑,修改基本项即可

缺点

Poly(WMC=53)和 Unit(WMC=50)逻辑过于复杂;太多方法集中在Poly类里了,复杂度过高

Definer.calFunc(v(G)=8)和 Unit.sinCosEqualHash(v(G)=20)需重构优化逻辑

仍然会出现面向过程的问题

在三角函数化简的方面仍然有做的不足的地方,需要加以改进

在实现处理-号时,把它当作了Term的一个属性,这个处理并不是很好,也导致了后面bug的产生

二、bug分析

  • 在第一次代码时我并未产生bug

  • 在第二次代码时我出现的bug集中在

​ 没有处理 sin(0)^0因为之前处理的时候只要系数为0就输出0,没有考虑到这条

​ 在递推函数替换字符串的时候,识别x,y进行替换,可能会出现重复替换的情况,修改替换顺序即可

​ 或者有一种更好的方法是先把x,y换成i,j这样无关的变量

​ 对题目要求识别不清晰,没有考虑到三角函数内的括号层数,在优化时对sin(2*x)只输出了一层

  • 在第三次代码时我的bug是

    由于我之前的Term项里有sign属性,但是在我clone的时候没有clone这个属性,导致出现问题,符号错误

    由于自定义函数在写的时候没有思考清楚,增加了不必要的字符串处理,反而写出来 bug

三、测试策略

测试策略是先输入一些自己犯过的bug,看看是否遇到同样的bug

然后针对于一些边界数据进行测试

看一下别人的代码,查看他容易出问题那部分的逻辑,比如递推函数等

不过仍然需要自己学习一下搭评测机,如果有评测机就可以更快的针对出错误点了

四、心得体会

在第一单元的学习中我投入了大量的时间,但由于自己的测试不够,细心不够,导致自己的强测成绩不够好,之后需要改掉自己的缺点。不过我确实提升了自己的编码能力,对递归下降的理解更加深入了,也渐渐理解了面向对象的好处。认识到了一些性能上的优化远没有正确性重要。

不弃微末,久久为功。在为没有被发现的bug而难过时,我也确实感受到了自己的进步。而学习可能就是这样的过程,虽然我可能现在做的不是很好,但是我确实在向前行走,相信我的代码会越写越好。

未来方向

我认为递推函数和自定义的函数实现很类似;可以把自定义普通函数换成一个其他的计算,或者把他们调换一下顺序。还有就是如果有教搭评测机的教程就更加好了.

...全文
32 回复 打赏 收藏 转发到动态 举报
写回复
用AI写文章
回复
切换为时间正序
请发表友善的回复…
发表回复

275

社区成员

发帖
与我相关
我的任务
社区描述
2025年北航面向对象设计与构造
学习 高校
社区管理员
  • Alkaid_Zhong
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧