OO第一单元总结
OO第一单元作业主题为表达式拆括号,三次作业分别为基本多项式拆括号,引入三角函数、自定义函数和求和函数,引入三角函数嵌套和自定义函数嵌套,下面我分享一下我在本单元的学习心得和作业完成情况。
第一次作业
整体结构分析及架构设计体验
第一次作业整体来说比较简单,最后的输出仅为一个简单多项式,难点就在表达式解析上面。首先我将整个表达式(Expression)按照加减号拆成若干个项(Item),每个项按照乘号拆成若干个因子(Factor),如果遇到乘方,则把乘方前面的部分重复的表示成index个因子,对于因子的处理则是判断其种类并存储其信息(针对常数和幂函数)或进一步将其当作表达式进行处理(针对表达式因子)。
在计算部分,我在本次作业使用BigDecimal数组进行计算过程的传参和最后答案的存储,最后每一项的输出形如:
BigDecimal[i]*x**i
$$
这里对于i = 0,1,2我进行了进一步优化,分别输出BigDecimal[0],BigDecimal[1] * x,BigDecimal[2] * x * x,同时,我对BigDecimal[i]为0,1,-1的情形也进行省略优化。
基于度量的代码结构分析
Method Metrics:
method | CogC | ev(G) | iv(G) | v(G) |
---|---|---|---|---|
MainClass.toString(BigDecimal[]) | 7.0 | 3.0 | 5.0 | 6.0 |
MainClass.stringJoint(String, BigDecimal, int) | 19.0 | 1.0 | 8.0 | 15.0 |
MainClass.main(String[]) | 2.0 | 1.0 | 2.0 | 2.0 |
Item.setPoly(String) | 16.0 | 1.0 | 9.0 | 9.0 |
Item.Item() | 0.0 | 1.0 | 1.0 | 1.0 |
Item.isFactor(String) | 10.0 | 2.0 | 4.0 | 9.0 |
Item.indexJudge(String) | 29.0 | 1.0 | 9.0 | 9.0 |
Item.calculate() | 18.0 | 1.0 | 7.0 | 10.0 |
Factor.setPoly(String) | 6.0 | 1.0 | 4.0 | 5.0 |
Factor.calculate() | 11.0 | 1.0 | 6.0 | 6.0 |
Expression.setPoly(String) | 8.0 | 1.0 | 6.0 | 6.0 |
Expression.isItem(String) | 10.0 | 2.0 | 4.0 | 9.0 |
Expression.Expression() | 0.0 | 1.0 | 1.0 | 1.0 |
Expression.calculate() | 4.0 | 1.0 | 3.0 | 4.0 |
Class Metrics:
class | OCAvg | OCMax | WMC |
---|---|---|---|
Expression | 3.75 | 5.0 | 15.0 |
Factor | 5.5 | 6.0 | 11.0 |
Item | 6.8 | 10.0 | 34.0 |
MainClass | 7.0 | 13.0 | 21.0 |
Total | 81.0 |
测试及debug
在本次作业中测截止前我对我的代码进行了肉眼看代码的正确性验证,使得我在强测以及互测中均没有被发现bug,在互测中,我主要针对了以下三点进行测试:0输出空串、超出long范围的整数和形如+008之类的指数,最后成功hack到一名同学。
第二次作业
本次作业个人感觉是三次作业里最难的一次,需要添加和重构的任务量甚至超出第一次作业的任务量,我的代码总行数相比第一次作业更是直接double
整体结构分析及架构设计体验
可以看到,在第二次作业中,第一次作业的表达式解析部分我基本全部沿用了下来,新增的四个类主要是计算模块取代第一次作业的BigDecimal数组,最后的输出由单纯的遍历数组输出变成了一个树状输出:
ExpressionInfo = \sum ItemInfo\\ ItemInfo = \sum (PowerFuncInfo*\prod TriFunc)\\ PowerFuncInfo = coefficient * x ** index\\ TriFunc = sin(coefficientIn * x ** indexIn)**indexOut\\ or\\ cos(coefficientIn * x ** indexIn)**indexOut
$$
本次作业的优化我没有进行三角函数的进一步优化,仅进行了第一次作业的优化和三角函数相乘时的合并同类项优化。
关于字符串替换
我在第二次和第三次作业中都使用了老师以及助教极度不推荐的字符串替换方法处理自定义函数和求和函数,理想中的字符串替换如下所示:
f(y) = y**2\\ f(1) = (1)**2
$$
可以看到,字符串替换在数学上是符合“带入“这一思想的,而在本次作业中也是一种幂函数因子到表达式因子的替换,并没有破坏整体结构。
但是,程序并没有自主意识(至少现在的科学发展阶段没有),它只会依照你的代码,不符合逻辑地、无脑的将一个字符串替换为另一个字符串,一个经典的例子,sin中的i在程序眼中于sum函数里的i没有任何区别,而且本次作业中三角函数内部不允许出现表达式因子,但字符串替换后有可能出现sin((1))这种情况,如果你的程序不支持sin里出现括号,这里就会直接报错。
一句话总结,字符串替换是一种理想很美好,但现实很残酷的做法。如果想不出bug,你可能就要彻底破坏原本表达式的结构(比如sin替换为SIN),这样写出的代码不仅可拓展性低,而且会很容易成为互测时被重点关注的对象。
基于度量的代码结构分析
Method Metrics:
method | CogC | ev(G) | iv(G) | v(G) |
---|---|---|---|---|
Expression.calculate() | 1.0 | 1.0 | 2.0 | 2.0 |
Expression.Expression() | 0.0 | 1.0 | 1.0 | 1.0 |
Expression.isItem(String) | 10.0 | 2.0 | 4.0 | 9.0 |
Expression.setPoly(String, HashMap) | 8.0 | 1.0 | 6.0 | 6.0 |
ExpressionInfo.add(ExpressionInfo) | 2.0 | 1.0 | 3.0 | 3.0 |
ExpressionInfo.ExpressionInfo() | 0.0 | 1.0 | 1.0 | 1.0 |
ExpressionInfo.multiply(ExpressionInfo) | 3.0 | 1.0 | 3.0 | 3.0 |
ExpressionInfo.negative() | 1.0 | 1.0 | 2.0 | 2.0 |
ExpressionInfo.powerFuncSetting(BigDecimal, BigDecimal) | 0.0 | 1.0 | 1.0 | 1.0 |
ExpressionInfo.settle() | 23.0 | 1.0 | 9.0 | 10.0 |
ExpressionInfo.toString() | 1.0 | 1.0 | 2.0 | 2.0 |
ExpressionInfo.triFuncSetting(TriFunc) | 0.0 | 1.0 | 1.0 | 1.0 |
Factor.calculate() | 4.0 | 1.0 | 4.0 | 4.0 |
Factor.isZero(String) | 4.0 | 1.0 | 6.0 | 7.0 |
Factor.setCustomFunction(String) | 12.0 | 3.0 | 7.0 | 8.0 |
Factor.setPoly(String, HashMap) | 11.0 | 1.0 | 11.0 | 11.0 |
Factor.setSumFunc(String) | 11.0 | 1.0 | 8.0 | 9.0 |
Factor.setTriFunc(String) | 5.0 | 1.0 | 5.0 | 5.0 |
Item.calculate() | 2.0 | 1.0 | 3.0 | 3.0 |
Item.indexJudge(String, HashMap) | 29.0 | 1.0 | 9.0 | 9.0 |
Item.isFactor(String) | 10.0 | 2.0 | 4.0 | 9.0 |
Item.Item() | 0.0 | 1.0 | 1.0 | 1.0 |
Item.setPoly(String, HashMap) | 16.0 | 1.0 | 9.0 | 9.0 |
ItemInfo.getOriginPowerFunc() | 0.0 | 1.0 | 1.0 | 1.0 |
ItemInfo.getPowerFunctions() | 0.0 | 1.0 | 1.0 | 1.0 |
ItemInfo.getTriFunctions() | 0.0 | 1.0 | 1.0 | 1.0 |
ItemInfo.ItemInfo() | 0.0 | 1.0 | 1.0 | 1.0 |
ItemInfo.multiply(ItemInfo) | 17.0 | 1.0 | 9.0 | 10.0 |
ItemInfo.negative() | 1.0 | 1.0 | 2.0 | 2.0 |
ItemInfo.powerFuncSetting(BigDecimal, BigDecimal) | 0.0 | 1.0 | 1.0 | 1.0 |
ItemInfo.sameTriFunc(ItemInfo) | 14.0 | 4.0 | 4.0 | 6.0 |
ItemInfo.setOriginPowerFunc(ArrayList) | 0.0 | 1.0 | 1.0 | 1.0 |
ItemInfo.setPowerFunctions(ArrayList) | 0.0 | 1.0 | 1.0 | 1.0 |
ItemInfo.settle() | 12.0 | 1.0 | 6.0 | 7.0 |
ItemInfo.setTriFunctions(ArrayList) | 0.0 | 1.0 | 1.0 | 1.0 |
ItemInfo.toString() | 31.0 | 1.0 | 12.0 | 13.0 |
ItemInfo.triFuncSetting(TriFunc) | 0.0 | 1.0 | 1.0 | 1.0 |
MainClass.main(String[]) | 15.0 | 1.0 | 8.0 | 8.0 |
PowerFuncInfo.getCoefficient() | 0.0 | 1.0 | 1.0 | 1.0 |
PowerFuncInfo.getIndex() | 0.0 | 1.0 | 1.0 | 1.0 |
PowerFuncInfo.multiply(PowerFuncInfo) | 0.0 | 1.0 | 1.0 | 1.0 |
PowerFuncInfo.negative() | 0.0 | 1.0 | 1.0 | 1.0 |
PowerFuncInfo.PowerFuncInfo(BigDecimal, BigDecimal) | 0.0 | 1.0 | 1.0 | 1.0 |
PowerFuncInfo.setCoefficient(BigDecimal) | 0.0 | 1.0 | 1.0 | 1.0 |
PowerFuncInfo.setIndex(BigDecimal) | 0.0 | 1.0 | 1.0 | 1.0 |
PowerFuncInfo.toString() | 18.0 | 1.0 | 12.0 | 12.0 |
TriFunc.addIndex(TriFunc) | 0.0 | 1.0 | 1.0 | 1.0 |
TriFunc.allSame(TriFunc) | 1.0 | 1.0 | 4.0 | 4.0 |
TriFunc.getCoefficientIn() | 0.0 | 1.0 | 1.0 | 1.0 |
TriFunc.getIndexIn() | 0.0 | 1.0 | 1.0 | 1.0 |
TriFunc.getIndexOut() | 0.0 | 1.0 | 1.0 | 1.0 |
TriFunc.isSin() | 0.0 | 1.0 | 1.0 | 1.0 |
TriFunc.sameTo(TriFunc) | 1.0 | 1.0 | 3.0 | 3.0 |
TriFunc.setCoefficientIn(BigDecimal) | 0.0 | 1.0 | 1.0 | 1.0 |
TriFunc.setIndexIn(BigDecimal) | 0.0 | 1.0 | 1.0 | 1.0 |
TriFunc.setIndexOut(BigDecimal) | 0.0 | 1.0 | 1.0 | 1.0 |
TriFunc.setSin(boolean) | 0.0 | 1.0 | 1.0 | 1.0 |
TriFunc.setTriFunc(String) | 23.0 | 1.0 | 10.0 | 12.0 |
Class Metrics:
class | OCAvg | OCMax | WMC |
---|---|---|---|
Expression | 3.25 | 5.0 | 13.0 |
ExpressionInfo | 2.75 | 9.0 | 22.0 |
Factor | 5.5 | 8.0 | 33.0 |
Item | 5.4 | 9.0 | 27.0 |
ItemInfo | 3.142857142857143 | 11.0 | 44.0 |
MainClass | 7.0 | 7.0 | 7.0 |
PowerFuncInfo | 2.375 | 12.0 | 19.0 |
TriFunc | 2.076923076923077 | 11.0 | 27.0 |
Total | 192.0 | ||
Average | 3.2542372881355934 | 9.0 | 24.0 |
测试及debug
本次作业我也很幸运的在互测及强测中没有被发现bug,在互测中,我主要针对了字符串替换可能出现的问题进行测试,因为同行最了解的就是同行,可惜最后没有hack到任何一名同学。
第三次作业
本次作业增加了三角函数和自定义函数的嵌套。
整体结构分析及架构设计体验
由于我在第二次作业中设计的结构已经支持了括号嵌套,因此本次作业我的整体结构相对于第二次作业仅在三角函数处进行了微调,括号内改为了一个Expression对象,同时为优化三角函数的合并同类项重写了equal方法。
TriFunc = sin((ExpressionInfo))**indexOut\\ or\\ cos((ExpressionInfo))**indexOut
$$
可以看到,这里用嵌套括号是为了规避例如sin(-x)的非法输出,本质上就是摆烂。
基于度量的代码结构分析
Method Metrics:
method | CogC | ev(G) | iv(G) | v(G) |
---|---|---|---|---|
TriFunc.toString() | 4.0 | 1.0 | 2.0 | 4.0 |
TriFunc.setTriFuncInfo(ExpressionInfo) | 0.0 | 1.0 | 1.0 | 1.0 |
TriFunc.setTriFunc(String, HashMap) | 2.0 | 1.0 | 1.0 | 2.0 |
TriFunc.setSin(boolean) | 0.0 | 1.0 | 1.0 | 1.0 |
TriFunc.setParentheses(Polynomial) | 0.0 | 1.0 | 1.0 | 1.0 |
TriFunc.setIndexOut(BigDecimal) | 0.0 | 1.0 | 1.0 | 1.0 |
TriFunc.sameTo(TriFunc) | 1.0 | 1.0 | 2.0 | 2.0 |
TriFunc.isSin() | 0.0 | 1.0 | 1.0 | 1.0 |
TriFunc.getTriFuncInfo() | 0.0 | 1.0 | 1.0 | 1.0 |
TriFunc.getParentheses() | 0.0 | 1.0 | 1.0 | 1.0 |
TriFunc.getIndexOut() | 0.0 | 1.0 | 1.0 | 1.0 |
TriFunc.allSame(TriFunc) | 1.0 | 1.0 | 3.0 | 3.0 |
TriFunc.addIndex(TriFunc) | 0.0 | 1.0 | 1.0 | 1.0 |
PowerFuncInfo.toString() | 18.0 | 1.0 | 12.0 | 12.0 |
PowerFuncInfo.setIndex(BigDecimal) | 0.0 | 1.0 | 1.0 | 1.0 |
PowerFuncInfo.setCoefficient(BigDecimal) | 0.0 | 1.0 | 1.0 | 1.0 |
PowerFuncInfo.PowerFuncInfo(BigDecimal, BigDecimal) | 0.0 | 1.0 | 1.0 | 1.0 |
PowerFuncInfo.negative() | 0.0 | 1.0 | 1.0 | 1.0 |
PowerFuncInfo.multiply(PowerFuncInfo) | 0.0 | 1.0 | 1.0 | 1.0 |
PowerFuncInfo.getIndex() | 0.0 | 1.0 | 1.0 | 1.0 |
PowerFuncInfo.getCoefficient() | 0.0 | 1.0 | 1.0 | 1.0 |
MainClass.main(String[]) | 15.0 | 1.0 | 8.0 | 8.0 |
ItemInfo.triFuncSetting(TriFunc) | 0.0 | 1.0 | 1.0 | 1.0 |
ItemInfo.toString() | 31.0 | 1.0 | 12.0 | 13.0 |
ItemInfo.setTriFunctions(ArrayList) | 0.0 | 1.0 | 1.0 | 1.0 |
ItemInfo.settle() | 12.0 | 1.0 | 6.0 | 7.0 |
ItemInfo.setPowerFunctions(ArrayList) | 0.0 | 1.0 | 1.0 | 1.0 |
ItemInfo.setOriginPowerFunc(ArrayList) | 0.0 | 1.0 | 1.0 | 1.0 |
ItemInfo.sameTriFunc(ItemInfo) | 26.0 | 6.0 | 6.0 | 10.0 |
ItemInfo.powerFuncSetting(BigDecimal, BigDecimal) | 0.0 | 1.0 | 1.0 | 1.0 |
ItemInfo.negative() | 1.0 | 1.0 | 2.0 | 2.0 |
ItemInfo.multiply(ItemInfo) | 17.0 | 1.0 | 9.0 | 10.0 |
ItemInfo.ItemInfo() | 0.0 | 1.0 | 1.0 | 1.0 |
ItemInfo.getTriFunctions() | 0.0 | 1.0 | 1.0 | 1.0 |
ItemInfo.getPowerFunctions() | 0.0 | 1.0 | 1.0 | 1.0 |
ItemInfo.getOriginPowerFunc() | 0.0 | 1.0 | 1.0 | 1.0 |
ItemInfo.equals(ItemInfo) | 21.0 | 1.0 | 10.0 | 14.0 |
Item.setPoly(String, HashMap) | 16.0 | 1.0 | 9.0 | 9.0 |
Item.Item() | 0.0 | 1.0 | 1.0 | 1.0 |
Item.isFactor(String) | 10.0 | 2.0 | 4.0 | 9.0 |
Item.indexJudge(String, HashMap) | 29.0 | 1.0 | 9.0 | 9.0 |
Item.calculate() | 2.0 | 1.0 | 3.0 | 3.0 |
Factor.setTriFunc(String, HashMap) | 5.0 | 1.0 | 5.0 | 5.0 |
Factor.setSumFunc(String) | 12.0 | 1.0 | 9.0 | 10.0 |
Factor.setPoly(String, HashMap) | 11.0 | 1.0 | 11.0 | 11.0 |
Factor.setCustomFunction(String) | 13.0 | 3.0 | 8.0 | 9.0 |
Factor.parenthesesNum(String, int) | 4.0 | 1.0 | 3.0 | 4.0 |
Factor.isZero(String) | 4.0 | 1.0 | 6.0 | 7.0 |
Factor.calculate() | 4.0 | 1.0 | 4.0 | 4.0 |
ExpressionInfo.triFuncSetting(TriFunc) | 0.0 | 1.0 | 1.0 | 1.0 |
ExpressionInfo.toString() | 1.0 | 1.0 | 2.0 | 2.0 |
ExpressionInfo.settle() | 23.0 | 1.0 | 9.0 | 10.0 |
ExpressionInfo.powerFuncSetting(BigDecimal, BigDecimal) | 0.0 | 1.0 | 1.0 | 1.0 |
ExpressionInfo.negative() | 1.0 | 1.0 | 2.0 | 2.0 |
ExpressionInfo.multiply(ExpressionInfo) | 3.0 | 1.0 | 3.0 | 3.0 |
ExpressionInfo.ExpressionInfo() | 0.0 | 1.0 | 1.0 | 1.0 |
ExpressionInfo.equals(ExpressionInfo) | 16.0 | 1.0 | 5.0 | 9.0 |
ExpressionInfo.add(ExpressionInfo) | 2.0 | 1.0 | 3.0 | 3.0 |
Expression.setPoly(String, HashMap) | 8.0 | 1.0 | 6.0 | 6.0 |
Expression.isItem(String) | 10.0 | 2.0 | 4.0 | 9.0 |
Expression.Expression() | 0.0 | 1.0 | 1.0 | 1.0 |
class Metrics:
class | OCAvg | OCMax | WMC |
---|---|---|---|
Expression | 3.25 | 5.0 | 13.0 |
ExpressionInfo | 3.4444444444444446 | 9.0 | 31.0 |
Factor | 5.285714285714286 | 8.0 | 37.0 |
Item | 5.4 | 9.0 | 27.0 |
ItemInfo | 3.933333333333333 | 11.0 | 59.0 |
MainClass | 7.0 | 7.0 | 7.0 |
PowerFuncInfo | 2.375 | 12.0 | 19.0 |
TriFunc | 1.3076923076923077 | 4.0 | 17.0 |
Total | 210.0 |
测试及debug
本次作业我同样在互测及强测没有被发现bug,在互测中,我针对sum里的数超过long构造数据hack到了一名同学。
心得体会
在本单元的学习中我初步体会了面向对象编程以及迭代开发的思想,深刻意识到了一个好的架构的重要性。
本单元我做的比较好的地方是对于表达式的拆分,这一部分我从第一次作业一直沿用到第三次作业,中间仅进行了小幅度修改,这就是一个好的架构。而我做的不好的地方就是第二次和第三次作业使用字符串替换的方法处理自定义函数和求和函数,虽然我没有被发现出bug,但这种做法本质上还是投机取巧的。俗话说,躲得过初一躲不过十五,接下来的多线程单元同样是oo课程的一个难点,如果再在作业中使用投机取巧的方法,那肯定是走不远的。
P.S: 下个月要与新主楼电梯为伴了(笑)