面向对象第一单元总结

余国帆-21373253 学生 2023-03-18 00:25:13

OO第一单元总结

写在前面

第一单元的主题是表达式的括号展开,学习的目标是感受面向对象的编程思想,掌握用类来管理对象的方法。针对本单元作业来说,便是通过对表达式结构进行建模,完成多变量多项式的括号展开,初步体会层次化设计的思想。

对于本单元的作业所需的前置知识,主要是Java 基础语法与基本容器的使用,扩展 BNF 描述的形式化表述,正则表达式、递归下降或其他解析方法。对于寒假摆烂的且上学期没有选上先导课的我来说,属实难顶。(不过根据课程组公开的数据,也有没上过先导课但是能够多次作业强测拿到90+的大佬。果然还是我太菜了

尽管磕磕绊绊,我还是活了下来。从第一周的痛苦爆0,到第三周的强测全过(尽管性能分稀烂),废话不多说,来分享一下我如何苟过三次作业(在屎山代码上不断打补丁)。

历次作业

hw1

问题分析

第一次作业还比较简单,主要是于多变量多项式的展开,这次我们需要展开的表达式中项只有四种——变量因子,幂函数因子,常数因子和表达式因子。

由于本人在第一周才开始学习java语法和递归下降,一开始属实难以动笔,直到完成了第一周的training,我才有了思路,直接基于实验的框架进行修改。

这次作业的主要难点在于对表达式的层次分析,而在课程组给出的框架中将其分成了ExprTermFactor,按三层来进行解析,这也是绝大多数人选择的方法。

经过对样例代码的分析,我初步决定了代码的整体框架。

预处理输入>>解析表达式>>输出化简

决定了框架后便是具体的实现方案。

实现方案

第一周的时候由于缓考等原因,我并未完成作业,到第二周才将第一次作业完善,因此我展现的是完善后的版本(感谢课程组允许补交,给了我重生的机会(≧∇≦)ノ)

代码结构展示

hw1代码的主要框架如下所示:

img

接下来解释各个类的作用:

Main:表达式输入及表达式化简(去除多余+-号及空白符)
Lexer:词法分析器,主要是解析表达式,判断接下来的部分是Term或是Factor或者Expr
ExprNumberVariable:三种因子类,均是接口Factor的子类
Term:项类
Parser:重点,层次化解析类
Mult:各因子相乘及项相乘的计算类,用于化简计算和输出

复杂度分析

img

很明显可以看到MultParser两个类的复杂度较高,原因是在其中堆积了过多方法,且存在复杂方法的耦合度较高,很容易出现错误

优缺点分析

hw1的框架在化简表达式上有几个笨拙但有用的优点:

1.输入预处理时,将多余正负号全部去除,处理数据时简化了大量控制流
2.考虑到个别项中存在Expr因子,为了简化输出难度和计算难度,每个项解析完后都会都会判断是否存在Expr因子,如果有就将其他因子与它相乘,最终得到仅有一个Expr因子的Term
3.在Expr中调用addTerm方法时便会判断是否有同变量的项,边化简边处理,减少了计算量

但也存在以下缺点:

1.在项中未对因子进行排序,在第一次作业时化简判断还比较容易,但到了第二次作业时,一旦变量因子和三角因子顺序变化,就无法进行有效化简
2.仅仅将ArraySet当作数组使用,没有利用到ArraySet的特点,这也是对Java不熟悉造成的
3.在架构最初不清楚java深浅克隆的特性,在写完测试时才发现这个问题,但没有对每个类进行重写克隆方法,而是增加了部分类的构造函数,为后面的拓展留下了坑

Bug分析

由于第一次作业是第二周bug修复时才写完,是对着数据点进行针对性补丁写完的,所以无法体现原有的bug,因此仅能通过打补丁的过程中的修改来分析存在的一些bug成因:

1.深浅克隆
2.方法耦合度过高,不易发现错误

hw2

问题分析

本次作业增加了三角函数与自定义函数,以及括号的多层嵌套。

首先多层括号嵌套,由于第一次作业时提前预测了多层括号的情况,不需要对解析方法做出改变,仅需对化简过程进行修改。

此外我们认为三角函数与简单幂函数同质,因此进新增了一个Tri类来存储和处理三角函数。

自定义函数可以分作两个部分处理,等号左侧确认函数变量个数及变量,右边当作普通的表达式处理,然后通过字符串的正则表达式替换可以实现函数的处理。为此我们新增了Func类来储存每个函数的处理结果及处理方法

实现方案

代码结构展示

img

可以看见类之间的耦合程度大大提高,很明显是问题的复杂度上升了。其实是因为我菜代码一坨屎山但是又不想重构
最主要的是新增了这三个类

Simplifier:用于字符串的前处理和后处理,TermFactor的化简,以及自定义函数的处理
Func:存储自定义函数,并提供表达式解析时替换函数内部变量的方法
Tri:存储三角函数及部分化简方法

类复杂度

img

相比第一次作业,ExprTerm这两个类的addTermaddFactor方法复杂度大大增加,因此导致这两个类的复杂度增加,复杂度和耦合度的增加大幅增加了我debug的难度,因此本次作业的强测成绩差强人意

优点分析

本次作业新增了几个特性我较为满意,也起到了很大的作用:

1.由于括号嵌套和Expr循环嵌套,导致一个Expr因子可能会嵌套多层Term和Expr外壳,增加解析难度,我增加了Factor的化简,Term中仅一个因子且为Expr时,检测是否该Expr因子是否也仅有一个Term及一个Factor,如果是,就可以将该Expr赋值为更深两层的Expr,降低递归深度
2.我们发现解析过的Expr复杂度仍然很高,但是当他调用toString方法后,新产生的表达式形式较为简单且不含多余括号,此时再次解析可以大大化简表达式复杂度

Bug分析

1.新增三角函数所造成的深浅克隆问题
2.函数因子的变量替换时,由于没有在外层套括号,转换出来的字符串可能会有未知的不符合文法的错误,导致解析出现问题
3.部分优化造成了新的bug,导致输出最终结果时会重复输出或计算部分因子。

hw3

问题分析

该次作业新增了求导因子,且自定义函数可以调用前面已经定义过的函数。
首先是自定义函数,由于第二次作业中对函数的解析与对表达式的解析复用同样的功能,解析表达式时可以对函数进行解析,解析函数时同样也可以,因此不需要多加处理。
其次是求导因子,求导因子看似复杂,但是只需要对几种Factor增加简单求导方法,在Term中利用链式法则,在Expr中利用加法求导,递归调用,即可轻松解决问题

实现方案

代码架构

由于前面的架构已经完成第三次作业的大部分要求,我仅仅增加了层次化的求导方法就完成了要求,而其他可能bug在前两次的bug修复中完成,本次作业成为了我耗时最少的一次,强测也全部通过。
求导方法利用了实验课上的架构,唯一不同的点在于实验课上将幂函数拆分成多个因子相乘利用链式法则求导,效率较低,我直接对幂函数求导,而三角函数也是做复合的幂函数利用复合函数求导规则完成求导,总体修改量不超过百行。
修改后代码架构如下图所示:

img

很明显类之间的耦合度又升高啦!
由于求导过程中涉及到TermExpr的合并,而合并需要调用Simplification类中的化简方法,像前两次那样将几个Factor类以及Term放入一个package的方法已经无法实现了,于是我将他们移出了package。而这造成的是更低的内聚和更高的外耦合。与老师的要求背道而驰。
不得不说,菜是原罪

总体心得

时间安排

这三周由于各种事情的堆积,每周开始写代码的时间几乎都是周四和周五才开始,开发压力极大,因此对于重构非常慎重,只能在已有的垃圾框架下进行修改和修补,难度极大。
同时由于开发时间紧凑,留给测试的时间很短,也没有太多时间写自己的评测机,只能寻求大佬的帮助,利用他们的评测机进行短时间的不完全不充分的测试,因此导致了第二次作业糟糕的强测得分。
在之后的单元中,需要尽早开始构思架构,且尽量在ddl前一到两天通过中测,以留足足够的时间优化代码,测试bug

知识点预习

第一单元吃了对java完全不熟的亏,(也是因为太懒了寒假没有提前预习),因此在之后的每单元开始前,比如这一周写博客的时候,利用空余的时间提前预习和了解下一个单元所需的知识点,比如下一单元的多线程。

交流经验

本单元的作业我基本是一个人自己琢磨着完成的,与同学的交流较少,因此吃了不少亏,在研讨课上与同学交流时,经常因为同学的发言产生豁然开朗之感,他山之石可以攻玉,之后需要更多的与同学交流,多翻看讨论区,能提高不少效率。

架构搭建

一定牢记面向对象代码的涉及原则:高内聚、低耦合,将问题进行层次分解抽象,再动手写代码前先规划好类之间的数据层次行为层次
如果到复杂的类或方法,分析他的数据和行为进行解耦,而不是为了简化而简化。
每单元三次作业中都有很强的递进性,需要给架构留下足够的可拓展空间。以此次作业为例,第一次作业就可以考虑,假如括号不止一层怎么办,假如变量名不止是x,y,z怎么办。

测试及Hack

大家可能注意到在之对历次作业的描述中,我基本没有提到过测试和Hack的部分,除了前面提到的时间紧任务重,还因为完全把测试交给了评测机随机生成数据,而没有自己独立针对性的手动生成数据。而在几次作业中也显示了,评测机随机性太大,且可能存在强度问题,手动生成配合评测机才能得到更好得效果。

再来分析我的程序本身,在实际的测试中我也发现,出现bug的方法或类,往往耦合度较高,代码复杂。而层次清晰,代码简洁的部分往往不会出现bug。

而在hack的时候我也发现了,评测机生成的数据有时候会出现强度过强的情况,无法通过合法性检测,这种时候就需要手动定位对方的bug在哪,将数据分段测试,力求以最小的数据hack对方。

收获

在这几周高强度的迭代开发中,我迅速掌握了Java的基本语法和一些常见类与方法的使用,也理解了递归下降的思想。对面向对象的原则和方法也有了清晰的认知(毕竟是从失败中收获的经验)。也基本清楚了OO这门课的学习方法。

...全文
33 回复 打赏 收藏 举报
写回复
回复
切换为时间正序
请发表友善的回复…
发表回复
发帖
2023年北航面向对象设计与构造

383

社区成员

2023年北京航空航天大学《面向对象设计与构造》课程博客
java 高校 北京·海淀区
社区管理员
  • 被Taylor淹没的一条鱼
  • 柠栀_Gin
加入社区
帖子事件
创建了帖子
2023-03-18 00:25
社区公告
暂无公告