第一单元总结性博客作业
架构设计
第一次作业
- 使用了递归下降的设计思路,设计表达式类(Expr)、项类(Term)、因子类(Factor)、幂函数类(PowerFunc)和符号整数类(SignNumber)层层调用实现整个表达式逻辑框架。
- 设计了一个安全读取类(SafeRead),用于逐个字符读取一个字符串,并且设计回溯方法,方便其他类调用。
- 在存储和合并数据方面,由于本次作业因子类型单一,选择使用HashMap<Integer, Integer>,每个键值对存储一个形如 a*x**b 的项,a为键值对中的value,存储系数;b为键值对中的key,存储指数。
- 设计了一个HashMap的运算类(Hashing),提供两张HashMap的加法运算和乘法运算方法,分别用于因子到项,项到表达式的合并;还提供一个clearEmpty方法,用于清除一张HashMap中value为0的键值对(系数为零,该项不存在)。
第二、三次作业
-
同样使用递归下降的思路下,因子内容丰富了许多,比第一次作业多设计了三角函数类(Triangle)、求和函数类(Sum)、自定义函数定义类(SelfFuncDef)和自定义函数调用类(SelfFuncCall)。
-
在识别到自定义函数定义时,创建新的SelfFuncDef对象,创建新的SafeRead对象,调用方法存储定义中的函数名、形参名,并且将等号之后的函数表达式用新的Expr类对象表示,递归解析,将解析完成的字符串储存为该函数定义对象的成员变量。最后再把所有函数定义存放在ArrayList
里以备之后SelfFuncCall对象使用。 -
识别到自定义函数调用因子时,通过函数名匹配对应的自定义函数定义对象,然后用调用对象的实参替换定义对象表达式成员变量中的形参字符,(因为有‘x’重复所以可以替换两次),然后将替换之后的字符串作为新的SafeRead对象的参数,将SafeRead对象作为新的Expr对象的参数进行解析,一切顿时又回到熟悉的步骤。
-
存储和合并数据方面,因为因子类型复杂很多,键值对不足以表示整个项,因此选择设计HashSet<HashMap<String, Integer>>。
其中每个HashSet可以表示一个多项式;HashSet的每个元素可以表示一项;而每个HashMap中都可以有特定的键值对,能表示幂函数因子,常数因子和三角函数因子,如:
- 幂函数 x**b : <"x", b>
- 常数因子 a :<"NUMBER", a> (这里的键值可以设为任何表达式中不可能出现的字符串)
- 三角函数因子 sin(...)**b : <"sin(...)", b>
-
由于数据存储方式改变了,还需要重新写Hashing类,将它改为HashSet的运算类,对public提供对两个HashSet的加法和乘法运算方法,对应多项式之间的加法和乘法。
-
改写了Expr类和Factor类的toString方法,这样就可以从将多项式从HashSet转化为无非必要括号的字符串了。
基于度量分析程序结构
经典OO度量
CogC 认知复杂度
ev(G) 基本复杂度是用来衡量程序非结构化程度的,非结构成分降低了程序的质量,增加了代码的维护难度,使程序难于理解。因此,基本复杂度高意味着非结构化程度高,难以模块化和维护。实际上,消除了一个错误有时会引起其他的错误。
iv(G) 模块设计复杂度是用来衡量模块判定结构,即模块和其他模块的调用关系。软件模块设计复杂度高意味模块耦合度高,这将导致模块难于隔离、维护和复用。模块设计复杂度是从模块流程图中移去那些不包含调用子模块的判定和循环结构后得出的圈复杂度,因此模块设计复杂度不能大于圈复杂度,通常是远小于圈复杂度。
v(G) 圈复杂度是用来衡量一个模块判定结构的复杂程度,数量上表现为独立路径的条数,即合理的预防错误所需测试的最少路径条数,圈复杂度大说明程序代码可能质量低且难于测试和维护,经验表明,程序的可能错误和高的圈复杂度有着很大关系。
第一次作业
Method | CogC | ev(G) | iv(G) | v(G) |
---|---|---|---|---|
Expr.expandingExpr(SafeRead) | 5 | 1 | 3 | 5 |
Expr.getTerms() | 0 | 1 | 1 | 1 |
Expr.toString() | 5 | 1 | 4 | 4 |
Factor.expandingFactor(SafeRead) | 17 | 1 | 8 | 8 |
Factor.getFactorHashMap() | 0 | 1 | 1 | 1 |
Factor.setFactorHashMap(HashMap<Integer, Integer>) | 0 | 1 | 1 | 1 |
Hashing.adding(HashMap<Integer, Integer>, HashMap<Integer, Integer>) | 4 | 1 | 3 | 3 |
Hashing.deleteEmpty(HashMap<Integer, Integer>) | 3 | 1 | 3 | 3 |
Hashing.muling(HashMap<Integer, Integer>, HashMap<Integer, Integer>) | 7 | 1 | 4 | 4 |
Main.main(String[]) | 4 | 1 | 9 | 9 |
PowerFunc.expandingPowerFunc(SafeRead) | 4 | 1 | 3 | 3 |
PowerFunc.getPowerHashMap() | 0 | 1 | 1 | 1 |
SafeRead.back() | 0 | 1 | 1 | 1 |
SafeRead.readC() | 1 | 1 | 2 | 2 |
SafeRead.setIndex(Integer) | 0 | 1 | 1 | 1 |
SafeRead.setLine(String) | 0 | 1 | 1 | 1 |
SignNumber.expandingSignNumber(SafeRead) | 4 | 1 | 4 | 5 |
SignNumber.getSignNumber() | 0 | 1 | 1 | 1 |
SignNumber.toString() | 0 | 1 | 1 | 1 |
Term.expandingTerm(SafeRead) | 9 | 1 | 4 | 7 |
Term.getFactors() | 0 | 1 | 1 | 1 |
Term.setSign(char) | 0 | 1 | 1 | 1 |
Total | 63 | 22 | 58 | 64 |
Average | 2.86 | 1.00 | 2.64 | 2.91 |
Class | OCavg | OCmax | WMC |
---|---|---|---|
Expr | 2.67 | 4 | 8 |
Factor | 3.33 | 8 | 10 |
Hashing | 3.33 | 4 | 10 |
Main | 3 | 3 | 3 |
PowerFunc | 2 | 3 | 4 |
SafeRead | 1.25 | 2 | 5 |
SignNumber | 2 | 4 | 6 |
Term | 2.67 | 6 | 8 |
Total | 54 | ||
Average | 2.45 | 4.25 | 6.75 |
第二、三次作业
Method | CogC | ev(G) | iv(G) | v(G) |
---|---|---|---|---|
Expr.expandingExpr(SafeRead, ArrayList |
5 | 1 | 3 | 5 |
Expr.getHashSetExpr() | 0 | 1 | 1 | 1 |
Expr.toString() | 3 | 1 | 3 | 3 |
Factor.expandingFactor(SafeRead, ArrayList |
9 | 1 | 6 | 12 |
Factor.factorE(SafeRead, ArrayList |
10 | 1 | 6 | 6 |
Factor.factorF(SafeRead, ArrayList |
0 | 1 | 1 | 1 |
Factor.factorN(SafeRead, ArrayList |
0 | 1 | 1 | 1 |
Factor.factorP(SafeRead, ArrayList |
0 | 1 | 1 | 1 |
Factor.factorS(SafeRead, ArrayList |
0 | 1 | 1 | 1 |
Factor.factorT(SafeRead, ArrayList |
0 | 1 | 1 | 1 |
Factor.getFactorHashSet() | 0 | 1 | 1 | 1 |
Factor.toString() | 3 | 1 | 3 | 3 |
Hashing.mapMuling(HashMap<String, Integer>, HashMap<String, Integer>) | 4 | 1 | 3 | 3 |
Hashing.setAdding(HashSet<HashMap<String, Integer>>, HashSet<HashMap<String, Integer>>) | 4 | 1 | 3 | 3 |
Hashing.setMuling(HashSet<HashMap<String, Integer>>, HashSet<HashMap<String, Integer>>) | 7 | 1 | 4 | 4 |
Main.main(String[]) | 5 | 1 | 8 | 8 |
Pow.expandPow(String, int, ArrayList |
6 | 1 | 4 | 5 |
Pow.getCut() | 0 | 1 | 1 | 1 |
Pow.getValue() | 0 | 1 | 1 | 1 |
PowerFunc.expandingPowerFunc(SafeRead, ArrayList |
5 | 1 | 3 | 6 |
PowerFunc.getPowerHashMap() | 0 | 1 | 1 | 1 |
SafeRead.back() | 0 | 1 | 1 | 1 |
SafeRead.readC() | 1 | 1 | 2 | 2 |
SafeRead.setIndex(Integer) | 0 | 1 | 1 | 1 |
SafeRead.setLine(String) | 0 | 1 | 1 | 1 |
SelfFuncCall.expandingSelfCall(SafeRead, ArrayList |
18 | 4 | 8 | 10 |
SelfFuncCall.getHashSetSelfCall() | 0 | 1 | 1 | 1 |
SelfFuncDef.expandingSelfFuncDef(String) | 19 | 1 | 7 | 11 |
SelfFuncDef.getExpression() | 0 | 1 | 1 | 1 |
SelfFuncDef.getName() | 0 | 1 | 1 | 1 |
SelfFuncDef.getVars() | 0 | 1 | 1 | 1 |
SignNumber.expandingSignNumber(SafeRead, ArrayList |
4 | 1 | 4 | 5 |
SignNumber.getSignNumber() | 0 | 1 | 1 | 1 |
SignNumber.toString() | 0 | 1 | 1 | 1 |
Sum.expandingSum(SafeRead, ArrayList |
23 | 1 | 9 | 9 |
Sum.getHashSetSum() | 0 | 1 | 1 | 1 |
Term.expandingTerm(SafeRead, ArrayList |
9 | 1 | 4 | 7 |
Term.getHashSetTerm() | 0 | 1 | 1 | 1 |
Term.setSign(char) | 0 | 1 | 1 | 1 |
Triangle.expandingTriangle(SafeRead, ArrayList |
12 | 1 | 5 | 6 |
Triangle.getHashMapTriangle() | 0 | 1 | 1 | 1 |
Total | 147 | 44 | 108 | 131 |
Average | 3.59 | 1.07 | 2.63 | 3.20 |
Class | OCavg | OCmax | WMC |
---|---|---|---|
Expr | 2.33 | 3 | 7 |
Factor | 2.33 | 6 | 21 |
Hashing | 3.33 | 4 | 10 |
Main | 4 | 4 | 4 |
Pow | 2 | 4 | 6 |
PowerFunc | 2 | 3 | 4 |
SafeRead | 1.25 | 2 | 5 |
SelfFuncCall | 4.5 | 8 | 9 |
SelfFuncDef | 2.5 | 7 | 10 |
SignNumber | 2 | 4 | 6 |
Sum | 5 | 9 | 10 |
Term | 2.67 | 6 | 8 |
Triangle | 3 | 5 | 6 |
Total | 106 | ||
Average | 2.59 | 5.00 | 8.15 |
类图
第一次作业
第二、三次作业
心得体会
- 一开始做时还是会手足无措,递归搞得人眼花缭乱,自动评测机也不会写,输出的结果字符串像是石乐志。但当想出合适的存储结构和完整的展开逻辑之后,代码方面就通畅多了。
- 还是没掌握好面向对象的思维,在想不清楚每个类的功能和应该保存的数据时,很容易陷入面向过程的逻辑,这个类里写一点,那个类里写一点,最后弄得乱七八糟。