2024 BUAA OO UNIT 1

林舒雅-22371132 学生 2024-03-21 15:12:31

HW4-Blog

目录

  • HW4-Blog
  • 1.基于度量分析程序结构
  • 1.1.框架综述
  • 1.2.度量分析
  • 2.架构设计体验
  • 3.Bug分析
  • 4.Hack策略分析
  • 5.优化分析
  • 6.心得体会
  • 7.未来方向

1.基于度量分析程序结构

1.1.框架综述

第一单元作业的最终框架如下:

img

可以看出,第一单元代码由3个部分组成:输入的预处理及词法解析、语法树的构建(递归下降)、计算(Poly类和Mono类),我有意识且尽力地做到了我能力范围内的高内聚低耦合。其中求导因子因其特殊性,需要在其内部进行求导计算,虽然具体的四则运算仍然在PolyMono中进行,但内聚性仍因此有所下降。

接下来对类的设计考虑进行补充说明。部分简短的描述已经体现在类图中,以下将补充复杂的、不便绘制在图中的考虑。

  • Const: 储存自定义函数集合,向Lexer提供,因此采用了单例模式。同时出于避免大量重复创建实例,为整个工程提供01-1BigInteger形式。
  • DerFac: 求导因子,求导操作只发生在需要转换为Poly时刻。因此类中也准备了derPoly()(对Poly求导)和derMono()(对Mono求导)计算方法。
  • 其他因子类:除存放因子的内容以外,都准备了toPoly方法,将其转换为Poly,以便进入计算。
  • Term: 内容是因子的集合。同样实现了toPoly()方法。
  • PolyMono:顾名思义,多项式和单项式,前者是后者的集合。计算和化简都在这两类中进行,所以都实现了深克隆方法、equal()hashcode()的重写。

1.2.度量分析

代码复杂度概览如下:

方法CogCev(G)iv(G)v(G)
Total338.0147.0254.0278.0
Average3.93023255813953481.70930232558139532.9534883720930233.2325581395348837

以下是方法节选,只选取了复杂度较高的部分。复杂的方法主要出现在词法解析计算部分。由于讨论的情况较多,所以采用了大量的if-else乃至嵌套结构,导致方法的内聚并不够理想。

方法CogCev(G)iv(G)v(G)
DerFac.derMono(Mono)26.010.010.010.0
Lexer.addToken(String)26.01.019.019.0
Lexer.callUdf(String, String, int)26.05.014.014.0
Mono.equals(Object)15.09.05.09.0
Mono.isFactor(String)19.08.013.016.0
Mono.toString()37.03.015.016.0
Poly.equals(Object)11.07.05.08.0
Poly.toString()34.09.015.018.0
PowFac.toPoly()29.05.017.017.0

本单元代码过千行,如下:

img

2.架构设计体验

词法解析、语法树生成和toPoly是一以贯之的设计,参考了课程组的提示。我的重构和设计考虑大部分都放在了计算部分上,即多项式Poly如何存储、互相计算。

第一次作业的因子只涉及常数、幂和表达式,表达式经过解析递归得到的因子应当只剩下常数和幂,即最终计算时有

由于形式单一,易于解析计算,因此第一次作业的计算最小单元直接采用了String

img

第二次作业,因子增加了自定义函数和指数函数。我意识到上述的ans表达式不再适用,应更新为显然用String是不现实的,解析和计算都将变得困难。

因此我额外构建了一个最小单元类,即Mono,用于存放部分。由于最小单元不再是不可变类String深浅拷贝带来的影响不可忽视。所以第二次作业的重心基本上在深拷贝的调整,也曾因hashcode()写得不恰当,导致HashMap无法正常工作。

至于自定义函数,我一开始就打算放在Const类中,其以单例模式向Lexer提供,Lexer识别实参和函数名,随后进行字符串替换。至此框架基本成型

第三次作业,增加了求导因子和自定义函数嵌套其他自定义函数。后者仍可沿用之前的框架解决。而求导因子,我增加了DerFac类,意在调用toPoly()时刻将内容求导再生成,如此生成的Poly将和第二次作业的Poly形式一致。总体而言,第三次作业工作量并不大。

自定义新的迭代情境:因子增加了三角函数,那么我相应地会设计对应的三角函数因子类,同时扩展Mono中的元素,在原来的xexp集合加入新成员。同时Poly和Mono的计算也要发生相应的调整。但我认为和新增指数函数的操作相似。而有趣的点在于三角函数的化简。

3.Bug分析

在第二次作业中,出现了问题,为同质bug-格式错误。究其原因,是当时并没有确切地明白因子的定义,以至于认为-x等应是因子。

我痛定思痛,认为这样的错误与我的设计有一定的联系。关于连续的正负号,我在解析因子时进行处理,这就给我留下了一个潜意识的暗示:因子的前面可以有一个或多个符号,换而言之符号不影响因子。

所幸设计是比较合理的,在5行内我就修复了这个bug。

我认为更好的设计或者锻炼,应该是在写正常代码外补充异常类,这是我在阅读互测房间内他人代码发现的,这能够很好地训练对形式化的理解。

由于这个bug来源于我的主观臆断,所以无从对比分析出现bug的方法与未出现bug的方法的差异。但是在第一部分中,我确实存在了部分方法复杂度过高的问题,在仔细阅读了这些特定代码后,我认为降低方法的复杂度,即降低方法内的耦合度,适当分离,实现高内聚。针对我的代码来说,肤浅地说,就是降低if-else嵌套的频率。

4.Hack策略分析

  • 手捏样例,构造极端值或代价。
  • 使用评测机。
  • 阅读代码,特别关注做了提取公因数的同学(除法可能出错),或复杂度过高的方法(往往容易出错)。

5.优化分析

  • 尽量选用正项作为结果的第一项
  • 若指数函数括号内容为数字,则将指数放进括号与其相乘得到结果。
  • 若Mono内指数函数数量为1,原样输出。
  • 若Mono内指数函数数量大于1,则将它们化为一个exp

考虑到正确性为第一位,我并没有做提取公因数的工作。

6.心得体会

本单元,第一次体会到了互测,也因为自己对指导书的阅读不清付出了被hack的代价。可谓过山车般惊心动魄的体验。

在过千行代码中,我越来越深刻地体会到面向对象思维,也一直有意地向高内聚低耦合的目标靠拢。但同时我也体会到自己对Java深层的方法和思维知之甚少,或许多多阅读源码是一件好事,明白那些看似拿来就用的方法的运行逻辑,不仅可以让自己在coding和debuging时更加清醒,更有助于写出自己的代码。

7.未来方向

我认为实验课的安排时间可以提早一些,周三距离中测只有一天多的时间。

除此之外,我认为第一单元的课程已经很好了,节奏拿捏得恰好。虽然有一定难度,但大家都能完成。

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

301

社区成员

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

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