BUAA-OO 第一单元总结

王暄雨-22182609 2024-03-21 22:16:34

第一次作业

  第一次作业是整个第一单元的基础,要求我们展开简单的表达式,当时我对面向对象的理解还太浅薄,所以程序写的更偏向于面向过程,导致架构非常不清晰。

 

架构分析

类图

  通过类图可以发现,我的Expr, Term和Factor都用一个HashMap<BigInteger,BigInteger>来表示,哈希表确实可以很好的表示 a*x^b 这种形式,但我并没有在代码中体现出这三个类本应有的关系,导致这三个类过于相似,没有接口也没有继承关系,这种设计是非常不合理的,这也使我在后面的扩展中经常从别的类复制粘贴一些代码,将求导等工作都放到了Expr这一个类中,而Factor和Term中就几乎没有后两次扩展的痕迹,这种结构显然扩展性弱且逻辑不清晰。下面是各个类的设计思路:

Expr:代表表达式a * x ^ b + c * x ^ d......,里面有加减项的方法,通过加减parseTerm()返回的Term不断更新自身的值。两个方法均通过HashMap的功能合并同类项。

Term:代表项,内有乘因子的方法,parseTerm()返回的Factor会与当前的Term相乘并合并同类项。

Factor:代表因子,因为(表达式)也属于一种因子,所以仍采取HashMap的设计,HashMap的key代表x的次数,value代表x的系数。

Parser:语法分析器,通过判断Lexer返回的符号类型调用各种函数解析表达式。

Lexer:词法分析器,将表达式拆分为一个个Parser可以解析的元素。

MainClass:读入,输出,调用函数。

 

代码规模

  由上图可知,Parser类和MainClass类的代码量较多。Parser负责语法分析,根据Lexer得到的符号来调用各种类的各种方法,因此码量较大比较正常。但按理来说MainClass应该只负责调用方法,组织各方法的先后逻辑关系,不应有这么大的代码量,而我将输出和性能优化的方法均放到了MainClass中,使其中的功能较复杂,结构混乱,这也是我第二次作业出bug的原因,在后面的作业中需要注意这个问题 。 

 

OO度量

  由上图可知MainClass类的复杂度较高,原因是因为我将输入输出的方法均放在了MainClass中,使MainClass复杂度明显高于其他类。  

  after为输出答案的方法,由于我并未在每个类中写toString函数,导致输出的工作都集中在after方法中,使该方法复杂度过高。如若将输出工作分配到各个类中,复杂度会大大减少。

 

bug分析

本次作业要求较少,强测和互测都未出bug,互测房里也并未出刀。但由于程序架构不够清晰,没有很好的运用面向对象思想,导致在扩展后面两次作业的功能时较为复杂,增加了后续debug的工作量。

 

优化

第一次作业的优化较为简单,优化空间较小。我通过Hashmap做乘法和加减法时已经完成了合并同类项这一步,因此我只需要优化系数和次数为0和1时的省略即可。这里有个易错点就是若结果最终为0,需要特判一下避免没有输出。另外由于第一项为正时可以省略一个正号,所以我将系数为正的项先输出,为负的后输出,这些优化步骤都放在了MainClass中,使我的代码简洁性下降,正确方法应该是新建一个类来专门做优化。

 

第二次作业

第二次作业在第一次作业的基础上新增了自定义函数和exp()函数,我选择新建一个Poly类代表结构:a * x ^ b * exp(expr)

对于exp()的乘法我选择直接将exp()中的表达式相加,保证每个表达式都能用Poly类表示。

对于自定义函数,我选择直接在预处理时进行递归的字符串替换,在这里我忽略了因子的替换必须在外面再套一层括号,因此出了大bug。

 

架构分析

类图

  在第二次作业中由于新添了exp(),所以我新建了一个Poly类,并把所有HashMap的Key类型换成了Poly,在Poly类中重写了hashcode和equals函数,以确保HashMap的各种功能正常。另外在MainClass中我还加入了对自定义函数的字符串替换函数。  

 

代码规模

   本次在各个类中都添加了一些方法,其实有很多方法的功能都是几乎一样的,但由于当时我并不会使用接口等方法所以增加了工作量。

 

oo度量

  第二次作业中我将自定义函数的字符串替换方法放到了MainClass中,并将MainClass中的输出化简方法添加了化简exp()的功能,这都使MainClass的复杂度上升。

  我此次出的bug均在MainClass中的字符串替换和输出化简方法中,这跟MainClass的复杂度过高,功能过于复杂有关,13.67远大于其他类的1.00、1.33等,调试的时候也非常不方便,代码可读性大大降低。这也证明了类的功能越复杂,码量越大,就越容易出错。在之后的作业中我会尽量满足一个类只负责一个功能,MainClass只负责调用各种方法,这样可以提高可扩展性,使代码更简洁,减少出错。

 

bug分析

我的bug

  这次作业的强测扣大分,错了三个点!有两个大bug,互测也被hack出来了。

  我是在exp()中的因子内容等于0时会输出exp(()),原因是因为我忘在递归输出的函数中加上表达式为0的判断。

  我的自定义函数处理采用了字符串替换的方法,由于没有考虑到自定义函数定义和调用的时候都有次方的情况所以并没有给替换后的因子加括号导致出了bug。

  如:

0
f(x) = x^5
f(x^5)
我的输出:x^5

 

房内小伙伴的bug

这次我一共hack成功8次,主要集中在以下几个点

1.exp((-x))缺少一层括号

0
exp(((-x)))
错误输出:exp(-x)

2.超时

0
exp(exp(exp(exp(exp(exp(exp(exp(exp(x)))))))))^3
超时无输出

3.函数嵌套调用出错

3
h(x,y) = (y*3+x^2)*2*x
g(z,y,x) = z+y+x
f(y,x,z) = (y+x)*z
f(h(x,(x+1)),0,(-g(x,1,x)))*g(x,x^2,(x+1))
输出错误

hack技巧:记录下自己写程序时做的易错的细节处理,如:输入0会不会有输出等,随着功能越来越多这些小细节反而容易出错,而且不易被中测强测查出。主要针对题目中新增的功能进行hack,对于超时的点可以先试试房内有无容易超时的同学,再多加计算和尝试得出不爆代价的样例。

 

优化

这次作业我并没有做太多优化,只是用Hashmap合并同类项保证每项最多有一个exp函数。有同学对exp内的表达式进行了提取公因数并比较长度是否变短,甚至还有同学会将exp中的某些项提出使里面的表达式有更大的公因数,从而使性能更好。

 

第三次作业

第三次作业新加了求导功能,且自定义函数定义时可用已定义的自定义函数。

对于求导,我在Parser里新加了求导函数的解析并在Expr中写了递归求导的方法。对于自定义函数,我修改了字符串替换的部分,避免了出现因两个函数实参重复而出现bug的情况,再在自定义函数读入时调用字符串替换函数即可。

 

架构分析

类图

 

  在第三次作业中,我在Expr中添加了求导函数,同时因为之前的架构的逻辑非常不合理,所以不得不在Expr中新增了几个运算的函数,这也让我意识到了合理运用接口、继承等方法的重要性。

 

代码规模

   第三次作业我在Expr中添加了求导方法,Parser中新增了对dx()的分析,Expr代码量增加较多但多为简单的运算方法。  

 

oo度量

  由上图可看出改动的MainClass, Expr, Parser的复杂度均有提升,MainClass的数值仍然最高。MainClass中字符串输出和预处理的函数复杂度过高,在之后的作业中我会汲取教训,将各种输入输出函数放在其他类中,保证MainClass布局清晰易懂。

 

bug分析

  我在本次作业的强测和互测中并未出bug,也未刀到人,且由于没有做exp(0)和提取公因数的优化所以性能分较低。下面是房内同学出的bug:

0
x-00
输出:x0

   我们需要特别注意处理值为0的表达式的输出格式是否正确。

 

架构设计体验

  这次作业总的来说迭代的时候代码的改动量并不算太大,但我的架构仍不清晰,还有很大的优化空间,感觉在迭代的时候只是碰巧没有遇见不好添加的内容,如像我解决自定义函数调用的方式是将h,g,f三个函数的实参替换成九个不重复的字母,这种办法显然可扩展性很低。

  若在第三次作业的基础上加上sin和cos函数,我需要新增sin和cos两个类,更改Poly的内容,将sin和cos的运算添加到表达式运算的方法中。对于两个新增函数的优化,我会新写两个方法通过三角函数公式来合并,此步骤最好能放在运算Expr的过程中进行,可以使程序的复杂度降低。我在扩展的时候可能会在求导的部分遇到困难,因为我之前的求导函数只集中在了Expr这一个类中,为了更好的可扩展性应该给每个类都写一个求导函数然后递归调用。

 

心得体会

  由于我并没有上过oopre,在假期也没有充分预习java的特性和面向对象的思想,所以在第一周的时候需要学习很多东西,压力较大,在设计程序架构时并未充分思考好各种情况,程序设计的并不精细,可拓展性较低,导致后面几周的程序越写越乱,在MainClass里面胡乱扔了很多东西,架构不清晰,代码不美观。

  通过第一单元,我意识到了每单元第一次作业的重要性,它是后面两周的基础,在后面的作业中我也会更谨慎的设计程序的框架,运用好面向对象的思想,合理运用拷贝、继承、接口等我之前并不熟悉的知识点,从面向过程转变为面向对象,设计好每个类,尽可能减少后面扩展功能的工作量。另外对于hack的技巧,我会记录下自己在写程序时险些写出的bug并用它们去hack,并找出题目中的一些细节描述,据此设计数据点。

未来方向

  我个人觉得第一单元的课程难度适中,指导书清晰,可以尝试让大家通过training等方式多接触一下面向对象的思想,这样有利于大家更快进入架构设计的状态。

 

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

301

社区成员

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

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