BUAA_OO 第一单元总结

陈伟杰-71066001 学生 2023-03-18 14:18:31

综述:在第一单元里主要是以解析,展开表达式,然后和并表达式这几个重点为背景,围绕这几个点打造了入门面对象的基本思想,在这个单元我主要还是采用了递归下降法作为核心,其设计模式主要是解释器模式,在这三次作业中我们会以迭代的方式限制了代码的耦合性和可扩展性,一是培养形成一个好的架构,二是代码的可扩展性和降低出错率。

第一次作业


第一次作业主要是变量多项式的括号展开,也就是说最后结果恒等即可,不用考虑嵌套括号,主要解题思路,解析表达式->后缀表达式(先定义优先级再去掉括号)->字符串运算(要用到hashmap的Keyset来获取答案),然后指数最终结果与过程中不会超过8。

UML图

img

img

自我点评的优点和缺点

优点:面向对象的思想

缺点:部分方法的复杂度很高,如果不处理好后续可能会冗余

复杂度

img

img

每个类的属性个数,方法个数,类总代码规模

img

img

从第一次的作业我们可以看到,复杂度还能在一个“自我接受”的范围,只是要控制一下Parser类和Expr类,这两个类的关联性太高同时也隐藏了很多爆炸的“雷”,我们可以看到Expr类的addsimplify模块的耦合度很高。

Expr 类:这个expr类设计的想法,是一个数字表达式,该类中的 addsimplify() 方法用于将 Expr 对象进行加法合并和化简。该方法使用一个 HashMap 对象存储每个项中相同因子的系数之和,并使用 HashSet 对象来表示因子集合。然后将 HashMap 中的每个项转换为一个 Term 对象,以便构造 Expr 对象。

Exprpow 类:表示该表达式的底数和指数

Number 类:一个数字对象的值,有一个hashcode的方法

Pow 类:实现多项式的基本运算

Term 类:项

Lexer 类:词法分析

MainClass类:主类

Parser 类:语法分析

Bug分析

首次在本地运行的时候发现自己对表达式的扩展理解出现了问题,因为当时是一直在做着训练指导书来做,所以导致我一开始的思想是按照“训练”的那个思维去做,导致在做输入输出的时候一下子把自己带到沟里去了,还有是在scan的出了问题,我一开始定义的是凡是count>1的时候我就给它输出Wrong Format!但我发现比如有两个不嵌套的括号这个样例就会直接把我给带入到Wrong Format,后面我直接把这个想法给去掉就可以了,然后由于我的第一次作业是补交形式的,所以未能进入互测环节观看其他同学代码。

第二次作业

首先理解了第二次作业指导书的意义,相比第一次,增加了三角函数,自定义函数的这样一个迭代开开发需求,所以我一下子的思路 重点是函数的拆解依旧使用Lexer Parser 这类型的解析器,定义一个方法用于展开自定义。

UML图

img

img

自我点评优点和缺点

优点:通过递归下降的方法

缺点:耦合性过高

复杂度分析

img

img

img

从这个复杂度可以知道我的第二次作业主要是自定义函数的简化还有替换函数和在Parser中trifactor方法,出了问题,也就是说复杂度高,这也导致后面的bug的问题,复杂度越高,耦合性越大,在这里我分析一下Parser的这个trifactor的方法为什么复杂度那么高? 原因如下:首先是无必要的判断分支太多了,if-else嵌套过多,个人觉得将一些复杂的判断和处理逻辑拆分成独立的函数,然后可以使用更高效的算法解析。

img

每个方法规模、每个方法的控制分支数目 我们可以看到ev(G)过高是方法模块化做的依旧不够好非常难维护,所以我们针对以下过高的方法来看看它们的方法规模和控制分支数目,因为这样才有参考意义。

img

Diyfunction类:一个自定义函数的类(因为第二次作业有这个需求)

Expr类:表达式的方法(可以看到有加乘的运算)

Exprpow类:这个类的作用是表示一个指数表达式,实现了Factor接口

Number类:该类主要用于表示一个数字,其中num变量存储了一个BigInteger类型的数值

Pow类:该类的实例用于实现多项式的基本运算,如复制自身、获取底数、获取指数、判断相等等

Sumfunction类:这段代码实现了一个“求和”函数,它实现了Function接口,该接口具有三个方法:copy,getRadix和getExp。Sumfunction类的构造函数将下限,上限,和待求和的内容(content)作为参数传递,并将它们存储在该类的私有变量中。simplify方法实现了对“求和”表达式的简化,它使用一个for循环来遍历从下限到上限的所有整数。在操作新content对象时,它首先检查它是否是Pow、Trifunction、Expr或其他类型的Factor对象。如果它是Pow类型的,则将i的幂值替换为指数的值,并将其添加到Term中。如果它是Trifunction类型的,则将i代入其中,并对结果进行处理。如果内容是Expr类型的,则将i代入其中并将其添加到Term中。

Term类:项

Totaldiyfunctions 类:包含了一个ArrayList类型的成员变量

Trifunction 类:该类具有一个带有三个参数的构造函数,此外,该类还实现了Function接口中的其他方法,包括copy(复制Trifunction对象)、getRadix(获取Trifunction对象的基数)和equals(比较两个Trifunction对象是否相等)。

Lexer 类:词法分析,用于解析包含数学表达式的输入字符串,在这个类我的设计就是用“比较”词的方法来形成,还有很多的方法,不同的方法不同的解析作用

MainClass 类:主类

Parser 类:语法分析

Bug解决

第二次作业是我三次作业中de的时间最长的,有一个测试点因为反复的出错,总结有几点,一是三角函数输出的正确格式,这很重要!比如sin(x+x),sin(2x)这些都是属于不合法的输出,正确的是sin((x+x)),sin((2x),也就是说sin里面如果是表达式,表达式必带括号,我可以对比这两者的合法性以及注意“括号”的问题,当自己以为一开始是括号的问题,无脑添加括号后再兴高采烈的去提交,发现还没过(啊啊啊啊), 后来对这测试点debug(这也是个方法,幸好我错的那个点有数据点提供,发现过后原来自己在化简这方面出了问题,化简过后就过了,但因为我进阶没过所以在此进入不了互测房间看他人代码(找他人bug)

第三次作业

我的第三次作业也是基于第二次作业的迭代开发,随着难度也是直线上升,这次作业新增求导因子支持求导操作,表达式支持嵌套,那么求导的话,我想到的方法就是derivate方法,同时也根据指导书所说的求导因子最多只能出现一次。

UML图

img

img

自我点评的优点和缺点

优点:结构依旧清晰可知,有面向对象的思想

缺点:复杂度太高,可扩展性不强,也就是说如果添加一个新的需求就要重新构造

复杂度分析

img

img

img

从这个复杂度的图片我们可以看到,一些第二次作业同样的方法在第三次作业竟然更加复杂了(思考)这难道我越写越差了?慢慢的有点看不懂自己的代码, 但有一些方法的复杂度也有在降低,有一定程度的优化了复杂度,不会让每个类的关联性那么密集,耦合性降低。

img

img

Diyfunction类:在这个类增加了derivate方法,是接口 "Function" 中的方法,表示求函数的导数。由于该类没有实现该方法,因此该方法的实现也返回 null。

Expr类:增加了几个方法 sintocos方法 和costosin方法sintocos()和derivate方法

sintoco()将恒等式 sin^2(x) + cos^2(x) = 1 应用于表达式中 sin^n(x) 形式的任何因 子,从而简化表达式。返回简化的表达式。

costosin():将恒等式 sin^2(x) + cos^2(x) = 1 应用于表达式中 cos^n(x) 形式的任何因子,从而简化表达式。返回简化的表达式。

Exprpow 类:添加了expand和derivate的方法,Expand方法:返回表达式的扩展形式。它创建一个新的“Expr”对象和一个 新的“Term”对象,将项添加到表达式中,然后将基数因子添加到项指数时间。

Number类:添加了derivate方法 equal的比较 还有hashcode

Pow类:增加了derivate的方法

Sumfunction 类:跟第二次作业的实现和作用都是一样

Term类:添加了removed 的这个方法,这个方法的主要是就是先比较,比如name的参数是否等于sin,如果是则创建一个新的Expr对象,如果content没有以负号开头则会返回一个Trifunction对象

Totaldiyfunctions 类:跟第二次作业一样

Trifunction 类:添加了derivate方法在这个三角函数的类

Lexer 类:添加了一个getderivate的方法

MainClass类:跟第二次作业唯一的不同是求导算子只能出现一次

Parser 类:添加了derivateFunction的方法

Bug解决

相比第二次作业的“第一次体验”这一次作业总体在debug 方面没那么多时间(在测试的时候顺便把第二次的也de出来了), 一开始只过了两个测试点,看了输入之后可能自己是不是少加了“-”号 导致输出不一样,加了负号之后我以为应该问题都不大的时候,依然还有几个测试点没过,然后我有注意到会不会我在解析第二个,第三个函数定义的时候,没有把之前已经读了的函数定义代入进去?但后面越改错误的点越来越多(但这时候其实我已经发现了我过了刚才没有 “过的测试点”,所以最后只是逻辑的小小改变即可,刚才我提到第二次作业的bug也在这次第三次作业修改了

第二次作业有个问题就是f(x,y,z)=x+y+z

​ f(z,y,x) 会将z赋给x,就变成y+2*z然后x复制给z就变成y+2x有错误

解决办法就是用中间变量 比如u代替x,v代替y,w代替z,再用z代替u,y代替v,x代替w,这次因为过了全部点所以可以进入互测的房间,感觉房间的同学的架构都写得很好,让我无处下手,只能慢慢欣赏和被人hack的份

架构体验
从第一次作业到第三次作业我都是采用了递归下降的方法,因为每一次的作业都是在原作业的基础上持续开发,并未经历过重构情况,整个框架大致上是不变的,但我有一直在想怎么“优化”我的架构,如何更高效的让每个类都不那么依靠,要不然出的bug 我很难找,总的来说,自己的第一单元的架构是“乱”但能“运行”。

体会感想
因为第一次接触面向对象的思想,所以在第一次作业还是比较保持了原有的编码思想,之前也没上过先导课,所以在第一单元的学习还是有点吃力,在整个单元的学习,我发现自己的问题是不怎么会优化代码,因为第一次单元的评测不是把性能时间看得很重,所以在下一个单元就要提前有这个意识,还有就是我没有那个“预判”意识,这句的意思就是我永远是靠着测试点给的数据去改,我应该要用 这个样例如果换成这样是不是就不行了的想法去做,总的来说第一单元对于我这种没有任何java基础来说是比较难,但你会发现其实这单元学习到很多,你会发现如何“分配”的让程序跑起来,享受在面向对象的乐趣。

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

444

社区成员

发帖
与我相关
我的任务
社区描述
2023年北京航空航天大学《面向对象设计与构造》课程博客
java 高校 北京·海淀区
社区管理员
  • 被Taylor淹没的一条鱼
  • 0逝者如斯夫0
  • Mr.Lin30
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

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