面向对象第一单元个人总结
作者:互联网
一、第一次作业
UML类图
第一次作业我依托训练的代码进行自己的构造,主要有三个部分:输入转换、表达式解析以及结果的计算与输出。其中,对于表达式的解析结果,我使用后缀表达式进行存储,以方便计算。此时,传入到最后一部分的就只有一串字符,满足低耦合的要求。整体上,使用training的语法分析模式,设计Processor类进行文法提取,并协助Parser进行语法分析。
ExpressionCheck清除输入中的空白字符。
Factor代表因子,存储了常数与x,以及他们的各种属性:指数、正负、绝对值等。此处融合在一起,虽然写起来方便,但不如构建新类继承父类的实现方式那样有良好的拓展性与可读性。因此,后面作业时对此处有较多修改。
Parser、Processor、Expression、Term、General等都用来进行表达式的解析,同时参考training实现了递归解析。表达式的层次关系也主要依靠这些类实现。
CalUnit中用BigInteger[8]记录各项,并实现了加法、乘法的运算,用来进行最后的运算。
优点:
递归下降满足多括号需求、整体思路明确、用数组计算简便、易于理解。
缺点:
factor类的可拓展性不高,同时CalUnit中储存单元的拓展性也很弱。在之后的作业中需要修改。
复杂度分析:
从上图中,可以看见整体复杂度与类的耦合度都较低,主要是字符串处理与判断时,相关方法的复杂度、相关类的非结构化程度较高。
hack思路:
针对前置正负号、0次方、大数范围等形式化表述中易错的点构造测试点,以及自身完成作业时的一些易错例子,进行互测。最终,用前置正负号成功地hack了一个人。
bug:
此次作业未发现bug,但性能需要提升,如x**2与正数前置。
二、第二次作业
UML类图
第二次作业相比于第一次作业增添了三角函数因子,以及自定义函数和求和函数。因为我认为我第一次作业解析较好,所以此次作业中我采用字符串替换的方法处理自定义函数以及求和函数,在替换时对替换部分两端填一层括号以满足表达式的层次要求。替换在读取到表达式后便进行操作。这样的做法虽然简单,但很容易出错。因此,此次作业的bug较多,强测只通过了七个点。
TriFunction继承Factor类,代表三角函数因子,但其余两种因子仍聚在Factor中,这也是我设计中不好的地方,导致Factor类过于臃肿,复杂度较高。
CalUnit类中存储单元我采用了HashMap<HashMap<String,int>,BigInteger>的形式,以满足多因子的表达形式。每一个HashMap<String,int>中只用*运算,外部哈希的每一项用+运算。
优点:
递归下降满足多括号需求、字符串替换简单、符合人类运算思路,储存单元。
缺点:
字符串替换的方法很容易产生bug,储存结构较为复杂、进行运算时容易出错,在化简上拓展性弱。
复杂度分析:
从上图中,可以看见由于采取字符串替换,更多的判断导致整体复杂度上升。同时,字符串的处理与解析,相关方法的复杂度、相关类的非结构化程度较高。
hack思路:
针对三角函数解析、次方解析与运算等形式化表述中易错的点构造测试点,以及自身完成作业时的一些易错例子,进行互测。最终,用三角函数解析:(sin(x) + cos(1)) * (sin(x)- cos(1)) 与 (sin(x)+cos(1))** +02 成功地hack了6次。
bug:
此次作业bug较多,主要是三角函数解析和求和函数解析时未考虑带符号整数情况,在字符串替换时导致内部混乱,无法解析。此外,还有指数解析未考虑+号以及0次方的情况。本次作业情况很糟糕,原因是未进行充分的测试以及贪图简单使用字符串替换。
三、第三次作业
第三次作业与第二次作业的构造基本相同,主要是改变了三角函数TriFunction类中因子的数据类型,由Factor变为Expression,可以在内部解析表达式而非简单的变量、常数因子。同时,函数的相互调用我采取的办法是:在字符串替换时,进行多次查找替换,直到不再有自定义函数和求和函数。增添了检查三角函数内因子是否需要增减括号以满足形式化表述与性能优化的方法。
优点:
有简单的优化处理、递归下降满足多括号需求、整体思路明确、在上一次作业的基础上修改较少,只需调用方法。
缺点:
字符串替换的方法很容易考虑不周,产生许多小bug,储存结构较为复杂、进行运算时容易出错,化简性能差,代码结构冗杂、拓展性差。
复杂度分析:
从上图中,可以看见与第二作业类似更复杂的字符串替换引起更多的判断进而导致整体复杂度再次上升。方法上检查三角函数、计算等字符串处理判断方法的复杂度仍较高、相关类的非结构化程度较高,MainClass不够简洁。
hack思路:
针对三角函数解析、数据范围等形式化表述中易错的点构造测试点,以及自身完成作业时的一些易错例子,进行互测。最终,用三角函数解析:sin(+0)+cos(sin(0)) 与用数据范围:sum(i,111111111111111,111111111111111,x) 成功地hack了2次。
bug:
此次作业bug相比上次明显减少,强测有三个点没过,主要是求和函数的数据范围以及字符串替换时的考虑不周导致内部混乱,无法解析。原因是未仔细阅读指导书以及未经过充分测试。
四、架构设计体验
第一次作业由于对设计思想不熟悉,导致依靠training进行架构设计,未理解将因子用类分开的好处,导致代码冗杂,侥幸通关。
第二次作业采取了不好的字符串替换方法,增添了自定义函数解析类以及继承Factor的三角函数因子类。不好的方法刀子需要考虑的情况很多,进而引起一系列小bug,如正负号、指数的解析。第二次作业整体架构还好,递归下降使得只需添加一些类便可满足要求。可见好的架构是一个项目的基础。
第三次作业是比较轻松的,由于第二次架构的完整性与拓展性,第三次作业中仅改变三角函数TriFunction类中因子的数据类型、增添了三角函数优化方法便完成了作业,再次证明了好的建构的重要性。从第二次作业的惨淡结果看,良好的方法选择也是必不可少的,否则会出现许多意想不到的情况。
五、心得体会
第一次接触面向对象编程,很不熟悉,几乎没有思路,借助training的帮助才懂得了一些,有了初步思路。在第一单元的学习收获颇丰,类似继承、接口等方法,以及一些容器的选择使用。与此同时,几次作业的结果让我明白了测试的重要性,测试的付出与最终的结果成正比,这是我这一单元得到的最大教训。另外,写代码不能想着偷懒,选择不合适的方法,否则bug会从各种各样的地方冒出来。本单元深化了我对工程化思维的认识,并期待在今后能够做得更好,不要再犯第一单元的错误。
标签:总结,三角函数,复杂度,作业,面向对象,字符串,解析,bug,单元 来源: https://www.cnblogs.com/ing2002/p/16056889.html