BUAA_OO_第一单元总结

本文总结了BUAAOO课程中关于程序结构分析、代码规模和复杂度评估,包括类的属性和方法分析,以及针对Expr和Term类的优化建议。讨论了UML类图和表达式处理,包括自定义函数、指数因子和求导功能。作者还分享了个人在bug分析和代码优化的心得体会。
摘要由CSDN通过智能技术生成

BUAA OO 第一单元总结

一、基于度量分析程序结构

  • 类的属性个数、方法个数分析

    类名属性个数方法个数
    MainClass01
    Parser210
    Lexer35
    Expr117
    Term216
    Factor(Interface)02
    Number18
    Var15
    Exp16
    Func46
    • 由表可知, Expr 类与 Term 类中的方法数偏多,可通过建立工具类改进。
  • 代码规模分析
    在这里插入图片描述

    • 项目总规模800+lines,其中 ParserExprTerm 类代码规模占主要部分。
  • 复杂度分析

    • 方法复杂度
      在这里插入图片描述

      • 其中 CogC (认知复杂度) 描述理解一段代码的难度, ev(G) (基本圈复杂度) 描述一段代码的非结构化程度, iv(G) (设计复杂度) 描述模块间的耦合程度, v(G) (圈复杂度) 描述一段代码结构的复杂程度。
      • 由图分析,方法复杂度较低,可读性较好。
    • 类复杂度
      在这里插入图片描述

      • 其中 OCavg 代表类的方法的平均循环复杂度, OCmax 代表类的方法的最高循环复杂度, WMC 代表类的总循环复杂度。
      • 由图分析, ParserExprTerm 类复杂度较高,应考虑建立工具类方法进行优化以降低复杂度。
  • UML类图
    在这里插入图片描述

    • 其中,红色字体方法为核心方法,绿色背景为 hw 2 新增内容,蓝色背景为 hw 3 新增内容。
    • Main 类负责读入自定义函数以及输入字符串表达式,并将处理(删除空白符)后的字符串传给 Lexer
    • Lexer 类负责对输入的字符串进行词法分析,将其分为不同的 token 并通过 next() 方法进行移动,通过 peek() 方法访问当前 token
    • Parser 类负责输入表达式的解析,其中还包含 parseTerm() 方法 与 parseFactor() 方法分别对因子进行解析
    • Expr 类负责管理Terms,并实现了表达式与因子相乘,表达式的展开与化简以及求导等方法
    • Term 类负责管理Factors,并实现了项与项相乘,项展开为表达式以及项的化简和求导等方法
    • Factor 为接口,并声明了toString方法和clone方法,由 numberVarExpExpr 类实现。
    • Number 类实现Factor接口,为常数因子
    • Var 类实现Factor接口,为变量因子(幂函数)
    • Exp 类实现Factor接口,为指数因子
    • Func 类存储函数名、函数形参自变量、函数表达式等,并通过MainClass中的funcList访问

二、架构设计

  • 第一次作业要求实现包含±*^的单层括号表达式的展开
    • 解析表达式得到表达式树,对每一项进行展开与化简,输出拼接得到新的不含括号的表达式。
    • 将每一项化为标准形式 a * x ^ b ,然后根据系数相等合并同类项后进行输出。
  • 第二次作业要求实现嵌套括号指数因子自定义函数
    • 发现第一次化简不到位,可能出现多余的 ‘+’ 号,于是新增 easyExpr() 方法对化简后的表达式进行进一步的化简。
    • 发现第一次的展开并不适用于多层括号,于是每解析一个表达式返回其展开后的表达式,对应新增方法 expandExpr()
    • 新增指数因子,新增 Exp 类实现 Factor 接口,同时实现指数相乘的方法,指数因子的指数存为表达式。
    • 新增自定义函数因子,新增 Func 类,用于存储函数名、函数形参自变量、函数表达式;在调用时,对形参进行字符串替换,得到自变量x的表达式,然后将该字符串进行表达式解析,返回化简表达式。
    • 最简项的变化:由 a * x ^ b -> a * x ^b [* exp(c)]
  • 第三次作业要求实现自定义函数中嵌套已定义函数表达式求导
    • 由于自定义函数调用时进行字符串替换,所以自定义函数中嵌套已定义函数不影响原自定义函数的调用过程,故此处无需修改。
    • 而对于表达式求导,新增对于标准项的求导方法 derive() ,先将表达式进行化简,然后对每一项求导并合并,对新的表达式再进行一次化简,返回新的最简表达式。
  • 最终设计在新迭代情景上的可扩展性
    • 支持自定义函数中包含求导因子,支持求导因子的嵌套

三、个人bug分析

  • 第一次作业中

    • 自测时发现化简消项后若项数为0,则会输出为空串不符合要求,于是对这种情况进行了特判,强制返回“0”。
    • 而由于构造数据不完善,导致在将项展开为表达式时,若项中含两个以上表达式因子,在进行表达式相乘后未及时将得到结果存入循环结果表达式,仅会返回第一个表达式与最后一个表达式相乘的结果,导致在强测和互测中出现bug。
  • 第二次作业

    • 自测时发现表达式相乘时其中项的符号会变化导致结果错误,究其原因是在对符号进行调整时直接改变了原项的符号值,发现问题后采用深拷贝解决;
    • 由于先前设计将符号放在了项所在的层,即将所有整数视为无符号整数,故在读取exp指数部分的因子时无法读取到负整数,导致解析错误;
    • 同样的错误还发生在函数调用解析实参因子时,同样无法正确读取负整数因子。
  • 第三次作业

    • 未发现bug

四、互测小结

  • 首先是将自己的易错样例进行提交,有效性较差,仅测出少部分bug;
  • 然后对同房间成员的代码进行阅读与测试,能够发现其中部分逻辑不严谨之处,最终设计出相应的测试用例进行hack,成功率较高。

五、心得体会

  • 先导课带来的帮助

    • Git的使用
    • OO工具链的使用
    • Java编程基础
    • 面向对象的基本思想
  • 个人优化

    • 先前代码耦合度过高,按照逻辑对部分方法进行拆分,使得方法复杂度与类复杂度降低
    • 化简方面:将非全负项表达式的首个正号化掉,使得输出更加简短
  • 总结与反思

    • 通过本单元的学习,对面向对象的基本思想如封装、接口等有了更深的体会,同时在对表达式的解析中体会到了递归下降思想的高深之处。虽然在可扩展性上进行了一定的优化,但是一直未进行支持多变量的代码重构,除此之外,指数表达式的化简也并未做到最简,希望将来能有好的思路解决这一问题。
  • 41
    点赞
  • 36
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值