2024 BUAA OO 第一单元总结

余欣实-22373040 学生 2024-03-21 12:08:36

目录

  • 一、三次作业的程序结构和度量分析
  • Homework1
  • Homework2
  • Homework3
  • 二、架构设计体验
  • 三、程序 bug 分析
  • 四、互测 bug 分析策略
  • 五、优化分析
  • 时间性能的优化
  • 输出长度的优化
  • 六、本单元学习心得体会
  • 七、未来方向
(2024 BUAA OO 第一单元总结)

一、三次作业的程序结构和度量分析

Homework1

  • 第一次作业架构的类图如下:

    img

    • 架构将表达式的分析与化简分离,用 Factor-Term-Index-Factor 的递归结构进行表达式的语法分析,再将得到的表达式树通过每个类的 simplify() 方法递归地转化成用于计算的 SimpExpr-SimpTerm 体系,进行合并同类项、表达式加法、表达式乘法等计算,并通过重载 toString() 方法输出最终化简结果
  • 代码的复杂度度量分析如下:

    img


    img


    img

    • 观察到一些方法的 ev(G) 即基本复杂度较高,说明函数非结构化成分较高,这使得代码的质量下降、难以理解和维护;同时 SimpExpr.toString() 方法的 iv(G) 即模块设计复杂度较高,说明该函数与其他模块关联复杂、耦合度高,难以隔离调试与复用
    • 其他大部分函数的复杂度均在合适范围内,设计时也充分利用了封装的面向对象思想,使得代码结构较为清晰,易于理解与调试

Homework2

  • 第二次作业架构的类图如下:

    img

    • 在保持整体架构不变的情况下,加入了新的类 Exp 实现 Factor 接口,用于指数函数的语法分析和计算
    • 同时加入了 Function 类对自定义函数的定义进行存储以便在表达式化简中进行调用
    • 对于 exp 相关输出长度复杂的优化问题也进行了分析并实现了部分优化
  • 代码的复杂度度量分析如下:

    img


    img


    img


    img

    • 观察到除与第一次作业相同的复杂度较高情况以外,新增的 SimpTerm.compareTo() 方法不仅有着较大的 ev(G) 即基本复杂度和 iv(G) 即模块设计复杂度,v(G) 即圈复杂度也较高,合理的预防错误所需测试的最少路径条数随之大幅增大,难以测试和维护;同样的,该方法的 CogC 即认知复杂度也较高,结构较为复杂,不易于阅读和理解
    • 代码中大部分方法都延续了第一次作业中良好的架构,整体上复杂度仍在合适范围内,结构依然清晰
    • 同时随着新的迭代加入了许多新的方法,SimpExpr 与 SimpTerm 的类复杂度进一步提高

Homework3

  • 第三次作业架构的类图如下:

    img

    • 在保持整体架构不变的情况下,加入了新的类 Derivative 实现 Factor 接口,用于导数的语法分析和计算
    • 对于 exp 相关输出长度复杂的优化问题也进行了进一步的分析与优化
  • 代码的复杂度度量分析如下:

    img


    img


    img


    img


    img

    • 可以观察到本次迭代并没有带来更多的复杂度问题,秉承着良好的开发理念,代码结构依然足够清晰,易于理解与调试
    • 但在用于优化 exp 相关输出的 SimpExpr.printExp() 函数中复杂度有所提高,其原因主要在于更多的优化代码的加入

二、架构设计体验

  • 本单元的作业中,我采取的架构在第一次作业时就已经初步形成,将表达式的分析与化简分离,用 Factor-Term-Index-Factor 的递归结构进行表达式的语法分析,再将得到的表达式树通过每个类的 simplify() 方法递归地转化成用于计算的 SimpExpr-SimpTerm 体系,进行合并同类项、表达式加法、表达式乘法等计算,并通过重载 toString() 方法输出最终化简结果
  • 这一架构的科学性与高扩展性为随后的两次作业奠定了良好的项目结构基础,随后的两次作业中只需要针对新增需求进行增添与微调,大大降低了完成迭代的时间成本。
  • 架构的高兼容性使得代码对于多种新迭代情景均可兼容:
    • 对于加入 sin、cos 等函数的情形,只需计算所使用的 SimpTerm 中加入每个化简项对应的三角函数信息即可
    • 对于多元多项式的化简、计算和求导,架构中已经实现,对于复杂的链式法则求偏导数换元的问题,也通过记录形如导数$$\frac{dy}{dx}\bigg|_{x=x_0}$$中的 y、x、x0 进行解决
    • 对于函数定义中加入导数运算,对于多元多项式的化简、计算和求导的情形已经能够实现

三、程序 bug 分析

  • 本次单元我只在第二次作业的公测和互测中出现了 bug:优化输出之后会出现表达式中 exp 因子指数为负数的情况
    • 主要原因一方面来自对指导书要求了解的不详尽,疏忽了指数不能为负数的要求
    • 另一方面在于实际代码书写中,对于表达式提取每一项的公因子的 SimpExpr.getGcd() 方法的初始值设置有误,没有将初始值取绝对值,不能保证函数返回值一定为正
  • 出现 bug 的 SimpExpr.getGcd() 方法只与 SimpExpr.printExp() 方法关联,而 SimpExpr.printExp() 方法各项复杂度都较高,复杂的方法结构必然会带来编写的疏忽和调试的困难
  • 针对这一情况,最好的办法就是尽量实现函数的提取和复用,通过高聚合来降低方法复杂度,为调试和错误排查创造有利条件

四、互测 bug 分析策略

  • 本单元的互测我主要采取黑盒测试的方式,通过生成大量测试数据对他人的程序进行测试,从中找到输出错误的样例,再逆向寻找代码中的错误出处
  • 这一方法虽然效率不高,但在自动化生成和比对的帮助下,同样也能在一定时间内有效地找到代码中的 bug

五、优化分析

  • 本单元作业中我对于代码的时间性能和输出长度进行了优化

时间性能的优化

  • 对于时间性能的优化,我将 SimpExpr 和 SimpTerm 类继承 Comparable 接口并重载 compareTo() 方法,在合并表达式中先进行排序,以减少合并过程中的比较次数,降低了时间复杂度
  • 优化之后尽管新增了方法、类复杂度有所增加,但其中方法复杂度并没有随之提高,代码整体复杂度依然较低,简洁性与正确性得到保持

输出长度的优化

  • 对于输出长度的优化,我在 SimpExpr 类中新增了 printExp() 方法,以提取 exp 函数内各项公因子为主要手段,根据不同场景对各种优化尝试进行比对,输出局部最优结果
  • 优化使得方法和类的复杂度大幅提高,简洁性大幅下降。这一问题主要是由于优化过程没有遵循面向对象的思想和方法,单纯的面向过程设计使得代码结构冗长,缺乏层次的区分与优化
  • 对此,最好的解决办法就是将优化算法进行抽象,区分层次,通过方法、类的增加和耦合解决问题

六、本单元学习心得体会

  • 本单元第一次作业就是一个很大的挑战。对于难以理解的递归下降问题,我也是通过不断的阅读公众号的教学讲解、参与实验以及课下讨论,最终理解了这一过程后,才完成了第一次作业的架构设计
  • 得益于 OOPre 先导课程的学习,我对于面向对象的思维和代码架构有了基本的认识和了解,也直接帮助了我第一次作业的架构定型,避免了作业迭代过程中的重构,为我的代码编写节省了大量的精力和时间
  • 通过本单元的学习,我复习并强化了面向对象与 java 语言的基本知识,对于数据的生成和自动化比对做出了新的尝试,对于递归以及优化等算法有了新的认识,可谓收获满满,为以后的面向对象学习打下了坚实的技术和精神基础

七、未来方向

  • 对于第一单元课程的改进,第二、三次作业虽然也有或多或少的挑战,但更多地来自具体代码细节上的补充与调整,尤其是第三次作业,整体难度较小,其难度分配可以在进行调整
  • 对于互测数据的代价计算还应进行改进,避免通过过于复杂的数据卡性能的方式进行 hack,以免与互测设置的目的与初衷背道而驰
...全文
60 回复 打赏 收藏 转发到动态 举报
写回复
用AI写文章
回复
切换为时间正序
请发表友善的回复…
发表回复

301

社区成员

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

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