OO2022第一单元总结
OO2022第一单元总结
第一单元内容是表达式化简,有一定的难度。三次作业迭代实现更多的功能。就个人而言,三次作业都延用了Parse->Simplify的流程,解析部分借用了编译中词法分析和语法分析的思想。简化部分分为拆括号和合并(不严格分开,可能为了性能交错进行)两部分。
在第二次作业出现了较大的问题,导致强测WA了很多点。第三次作业进行了重构,效果比较好。
第一次作业
概述
第一次作业较为简单,不难分析得出所有项都可以化成a*x**b
的形式,这为合并带来了很大的简化(也为第二次架构崩坏埋下了伏笔)。
UML
分析
input expr --Tokenizer--> Token --Parser--> ExprNode(AST) --Simplifier--> BasicTerm --> output expr
如上将表达式化简的任务划分到Tokenizer词法分析器,Parser语法分析器,Simplifier简化器,实现功能解耦。而Token
,AST
,BasicTerm
在上述类组成的流水线中最终处理得到简化的表达式。
就后两次作业的情况这种抽象方式扩展性尚可,词法分析器器和语法分析器与简化过程解耦,在第一次和第二次作业只做了少量修改,在第二次到第三次作业没有进行任何修改(因为使用递归下降法,所以其实在第一次作业就是支持多层嵌套的)。而简化部分由于第二次作业设计失误在第三次进行了很多重构。
使用不可变的对象是减少bug的一种有效方法。在第一次作业中,Token
,ExprNode
,BasicTerm
都是不可变的(在第三次作业开了可变的口子就出现了和深复制相关的奇怪的bug)。
在设计Token
的表示形式的时候是在模拟C的tagged union。
struct Token{
enum TokenType type;
union{
char* str;
int num;
}data;
}
大概是这种形式,感觉不是非常的面向对象,但是如果实现一堆继承Token
的子类又会过度抽象。
在对表达式树进行建模的时候使用了继承多态,工具报了一堆Unutilized Abstraction
。
可能还是我的建模不是很合理,应该寻找表达式树每一个层级的共性抽取一个父类(如都存在一个方法化简自己),而且Simplifier
类里用一系列静态方法进行化简也不是很好。
度量值
Project Name ,Package Name ,Type Name ,MethodName ,LOC ,CC ,PC
proj1 ,(default package) ,BasicTerm ,getFac ,3 ,1 ,0
proj1 ,(default package) ,BasicTerm ,getIdx ,3 ,1 ,0
proj1 ,(default package) ,BasicTerm ,BasicTerm ,4 ,1 ,2
proj1 ,(default package) ,BasicTerm ,BasicTerm ,4 ,1 ,0
proj1 ,(default package) ,BasicTerm ,mul ,3 ,1 ,1
proj1 ,(default package) ,BasicTerm ,add ,3 ,1 ,1
proj1 ,(default package) ,BasicTerm ,negate ,3 ,1 ,0
proj1 ,(default package) ,BasicTerm ,merge ,18 ,5 ,1
proj1 ,(default package) ,BasicTerm ,multiply ,9 ,3 ,2
proj1 ,(default package) ,BasicTerm ,negateAll ,6 ,2 ,1
proj1 ,(default package) ,BasicTerm ,toString ,25 ,7 ,0
proj1 ,(default package) ,BasicTerm ,printExpr ,14 ,4 ,1
proj1 ,(default package) ,ExprNode ,getPow ,3 ,1 ,0
proj1 ,(default package) ,ExprNode ,VarFactor ,3 ,1 ,1
proj1 ,(default package) ,ExprNode ,toString ,3 ,1 ,0
proj1 ,(default package) ,ExprNode ,getValue ,3 ,1 ,0
proj1 ,(default package) ,ExprNode ,ConstFactor ,3 ,1 ,1
proj1 ,(default package) ,ExprNode ,toString ,3 ,1 ,0
proj1 ,(default package) ,ExprNode ,getPow ,3 ,1 ,0
proj1 ,(default package) ,ExprNode ,getExpr ,3 ,1 ,0
proj1 ,(default package) ,ExprNode ,ExprFactor ,4 ,1 ,2
proj1 ,(default package) ,ExprNode ,toString ,3 ,1 ,0
proj1 ,(default package) ,ExprNode ,Term ,4 ,1 ,2
proj1 ,(default package) ,ExprNode ,getExprNodes ,3 ,1 ,0
proj1 ,(default package) ,ExprNode ,getPrefixOperator ,3 ,1 ,0
proj1 ,(default package) ,ExprNode ,toString ,3 ,1 ,0
proj1 ,(default package) ,ExprNode ,getTerms ,3 ,1 ,0
proj1 ,(default package) ,ExprNode ,getPrefixOperators ,3 ,1 ,0
proj1 ,(default package) ,ExprNode ,Expr ,4 ,1 ,2
proj1 ,(default package) ,ExprNode ,toString ,3 ,1 ,0
proj1 ,(default package) ,VarFactor ,getPow ,3 ,1 ,0
proj1 ,(default package) ,VarFactor ,VarFactor ,3 ,1 ,1
proj1 ,(default package) ,VarFactor ,toString ,3 ,1 ,0
proj1 ,(default package) ,ConstFactor ,getValue ,3 ,1 ,0
proj1 ,(default package) ,ConstFactor ,ConstFactor ,3 ,1 ,1
proj1 ,(default package) ,ConstFactor ,toString ,3 ,1 ,0
proj1 ,(default package) ,ExprFactor ,getPow ,3 ,1 ,0
proj1 ,(default package) ,ExprFactor ,getExpr ,3 ,1 ,0
proj1 ,(default package) ,ExprFactor ,ExprFactor ,4 ,1 ,2
proj1 ,(default package) ,ExprFactor ,toString ,3 ,1 ,0
proj1 ,(default package) ,Term ,Term ,4 ,1 ,2
proj1 ,(default package) ,Term ,getExprNodes ,3 ,1 ,0
proj1 ,(default package) ,Term ,getPrefixOperator ,3 ,1 ,0
proj1 ,(default package) ,Term ,toString ,3 ,1 ,0
proj1 ,(default package) ,Expr ,getTerms ,3 ,1 ,0
proj1 ,(default package) ,Expr ,getPrefixOperators ,3 ,1 ,0
proj1 ,(default package) ,Expr ,Expr ,4 ,1 ,2
proj1 ,(default package) ,Expr ,toString ,3 ,1 ,0
proj1 ,(default package) ,Main ,main ,9 ,1 ,1
proj1 ,(default package) ,Parser ,getPos ,3 ,1 ,0
proj1 ,(default package) ,Parser ,getExpr ,3 ,1 ,0
proj1 ,(default package) ,Parser ,Parser ,6 ,1 ,1
proj1 ,(default package) ,Parser ,parse ,4 ,1 ,0
proj1 ,(default package) ,Parser ,expr ,19 ,4 ,0
proj1 ,(default package) ,Parser ,term ,42 ,11 ,0
proj1 ,(default package) ,Parser ,varFactor ,12 ,3 ,0
proj1 ,(default package) ,Parser ,number ,24 ,5 ,0
proj1 ,(default package) ,Parser ,constFactor ,4 ,1 ,0
proj1 ,(default package) ,Parser ,exprFactor ,20 ,4 ,0
proj1 ,(default package) ,Parser ,isAtEnd ,3 ,1 ,0
proj1 ,(default package) ,Parser ,peek ,3 ,1 ,0
proj1 ,(default package) ,Parser ,advance ,3 ,1 ,0
proj1 ,(default package) ,Parser ,consume ,9 ,2 ,1
proj1 ,(default package) ,Simplifier ,simplify ,3 ,1 ,1
proj1 ,(default package) ,Simplifier ,simplifyExpr ,13 ,3 ,1
proj1 ,(default package) ,Simplifier ,simplifyTerm ,11 ,3 ,1
proj1 ,(default package) ,Simplifier ,simplifyFactor ,24 ,5 ,1
proj1 ,(default package) ,Token ,Token ,5 ,1 ,3
proj1 ,(default package) ,Token ,getSymbol ,3 ,1 ,0
proj1 ,(default package) ,Token ,getNumber ,3 ,1 ,0
proj1 ,(default package) ,Token ,getType ,3 ,1 ,0
proj1 ,(default package) ,Token ,toString ,10 ,3 ,0
proj1 ,(default package) ,Tokenizer ,Tokenizer ,6 ,1 ,1
proj1 ,(default package) ,Tokenizer ,getTokens ,3 ,1 ,0
proj1 ,(default package) ,Tokenizer ,run ,48 ,12 ,0
proj1 ,(default package) ,Tokenizer ,number ,17 ,3 ,0
proj1 ,(default package) ,Tokenizer ,peek ,8 ,2 ,0
proj1 ,(default package) ,Tokenizer ,peek2 ,8 ,2 ,0
proj1 ,(default package) ,Tokenizer ,advance ,3 ,1 ,0
proj1 ,(default package) ,Tokenizer ,isAtEnd ,3 ,1 ,0
Project Name ,Package Name ,Type Name ,NOF ,NOPF ,NOM ,NOPM ,LOC ,WMC ,NC ,DIT ,LCOM ,FANIN ,FANOUT
proj1 ,(default package) ,BasicTerm ,2 ,0 ,12 ,12 ,99 ,28 ,0 ,0 ,0.16666666666666666 ,0 ,0
proj1 ,(default package) ,ExprNode ,8 ,0 ,18 ,18 ,77 ,18 ,0 ,0 ,0.2222222222222222 ,0 ,0
proj1 ,(default package) ,VarFactor ,1 ,0 ,3 ,3 ,12 ,3 ,0 ,0 ,0.0 ,0 ,0
proj1 ,(default package) ,ConstFactor ,1 ,0 ,3 ,3 ,12 ,3 ,0 ,0 ,0.0 ,0 ,0
proj1 ,(default package) ,ExprFactor ,2 ,0 ,4 ,4 ,17 ,4 ,0 ,0 ,0.0 ,0 ,0
proj1 ,(default package) ,Term ,2 ,0 ,4 ,4 ,17 ,4 ,0 ,0 ,0.0 ,0 ,0
proj1 ,(default package) ,Expr ,2 ,0 ,4 ,4 ,17 ,4 ,0 ,0 ,0.0 ,0 ,0
proj1 ,(default package) ,Main ,0 ,0 ,1 ,1 ,11 ,1 ,0 ,0 ,-1.0 ,0 ,0
proj1 ,(default package) ,Parser ,4 ,0 ,14 ,4 ,161 ,37 ,0 ,0 ,0.21428571428571427 ,0 ,0
proj1 ,(default package) ,Simplifier ,0 ,0 ,4 ,1 ,53 ,12 ,0 ,0 ,-1.0 ,0 ,0
proj1 ,(default package) ,Token ,3 ,0 ,5 ,5 ,29 ,7 ,0 ,0 ,0.0 ,0 ,0
proj1 ,(default package) ,Tokenizer ,4 ,0 ,8 ,3 ,102 ,23 ,0 ,0 ,0.0 ,0 ,0
词法和语法分析存在CC圈复杂度较高的问题(都是固定写法,虽然逻辑较为复杂但是读起来还是比较清晰),其他部分复杂度尚可,BasicTerm
内聚缺乏度较高(第二次作业崩掉的祸根之一)。
Bug
本次作业Bug较少,只发现了一个爆Long的错误,改成BigInteger
就对了。第一次作业比较简单,在同学们热情的hack下应该不会潜藏什么Bug?
第二次作业
概述
第二次作业属于是迭代开发失败。强行用第一次作业的架构增加第二次作业的功能,比如第一次对基本项a*x**b
的抽象已经不是很适用了,我却根据数据限制的嵌套层数条件在上面打补丁,导致最终BasicTerm
显得不伦不类。还在解析表达式树的代码中加入了很多数据限制相关的特判,导致复杂度加大,难以维护。
其实本来就采用了递归的方法,就应该直接用第三次作业取消嵌套限制后的写法,这样代码结构还会更加统一。
UML
分析
方法上和第一次作业基本相同,但是由于加入了三角函数,项不能统一成a*x**b
的结构了,但是由于数据限制,三角函数里只能有幂函数因子,而且只能有一层,于是直接将其硬写进BasicFactor
,这就是facInner
和idxInner
两个奇怪的数据的由来(最后还是不得不重构)。而由于使用ArrayList
储存因子和项,为了判断”可以合并“,需要一种”标准形式”,于是想到进行排序并提取项的系数部分,让其变为fac * (1*x**b) * (1*x**c) ....
的形式(中间不一定是x,也可能是三角函数)。
可以看出上述方法依赖于数据限制,可想而知有很多特判,复杂度很高。
同时,代码中用ArrayList<BasicTerm>
建模表达式,这显然不符合封装规则,也确实给我的编码带来了大量的麻烦,在第三次作业进行了重构。
度量值
Project Name ,Package Name ,Type Name ,MethodName ,LOC ,CC ,PC
proj2 ,(default package) ,BasicFactor ,BasicFactor ,7 ,1 ,5
proj2 ,(default package) ,BasicFactor ,createX ,3 ,1 ,2
proj2 ,(default package) ,BasicFactor ,createCos ,3 ,1 ,4
proj2 ,(default package) ,BasicFactor ,createSin ,3 ,1 ,4
proj2 ,(default package) ,BasicFactor ,merge ,30 ,7 ,1
proj2 ,(default package) ,BasicFactor ,isTriangleZero ,3 ,1 ,0
proj2 ,(default package) ,BasicFactor ,isTriangleOne ,3 ,1 ,0
proj2 ,(default package) ,BasicFactor ,canMerge ,3 ,1 ,2
proj2 ,(default package) ,BasicFactor ,equalsAll ,11 ,4 ,2
proj2 ,(default package) ,BasicFactor ,getFactorString ,25 ,7 ,3
proj2 ,(default package) ,BasicFactor ,klone ,3 ,1 ,0
proj2 ,(default package) ,BasicFactor ,getFactorType ,3 ,1 ,0
proj2 ,(default package) ,BasicFactor ,getFacInner ,3 ,1 ,0
proj2 ,(default package) ,BasicFactor ,getIdxInner ,3 ,1 ,0
proj2 ,(default package) ,BasicFactor ,getFac ,3 ,1 ,0
proj2 ,(default package) ,BasicFactor ,setFac ,3 ,1 ,1
proj2 ,(default package) ,BasicFactor ,getIdx ,3 ,1 ,0
proj2 ,(default package) ,BasicFactor ,setIdx ,3 ,1 ,1
proj2 ,(default package) ,BasicFactor ,compareTo ,33 ,7 ,1
proj2 ,(default package) ,BasicFactor ,equals ,10 ,3 ,1
proj2 ,(default package) ,BasicFactor ,hashCode ,3 ,1 ,0
proj2 ,(default package) ,BasicFactor ,toString ,13 ,3 ,0
proj2 ,(default package) ,BasicTerm ,BasicTerm ,4 ,1 ,2
proj2 ,(default package) ,BasicTerm ,BasicTerm ,5 ,1 ,0
proj2 ,(default package) ,BasicTerm ,merge ,18 ,5 ,1
proj2 ,(default package) ,BasicTerm ,multiply ,10 ,3 ,2
proj2 ,(default package) ,BasicTerm ,negateAll ,6 ,2 ,1
proj2 ,(default package) ,BasicTerm ,printExpr ,16 ,4 ,1
proj2 ,(default package) ,BasicTerm ,getBasicFactors ,3 ,1 ,0
proj2 ,(default package) ,BasicTerm ,getFac ,3 ,1 ,0
proj2 ,(default package) ,BasicTerm ,klone ,4 ,1 ,0
proj2 ,(default package) ,BasicTerm ,mul ,6 ,1 ,1
proj2 ,(default package) ,BasicTerm ,add ,3 ,1 ,1
proj2 ,(default package) ,BasicTerm ,negate ,3 ,1 ,0
proj2 ,(default package) ,BasicTerm ,extractFactor ,5 ,1 ,0
proj2 ,(default package) ,BasicTerm ,toString ,24 ,6 ,0
proj2 ,(default package) ,CustomFunction ,CustomFunction ,4 ,1 ,2
proj2 ,(default package) ,CustomFunction ,registerFunction ,3 ,1 ,2
proj2 ,(default package) ,CustomFunction ,getFunction ,3 ,1 ,1
proj2 ,(default package) ,CustomFunction ,eval ,7 ,2 ,1
proj2 ,(default package) ,ExprNode ,wrapNode ,10 ,1 ,1
proj2 ,(default package) ,ExprNode ,PowerFactor ,4 ,1 ,2
proj2 ,(default package) ,ExprNode ,getPow ,3 ,1 ,0
proj2 ,(default package) ,ExprNode ,getSymbol ,3 ,1 ,0
proj2 ,(default package) ,ExprNode ,toString ,3 ,1 ,0
proj2 ,(default package) ,ExprNode ,klone ,3 ,1 ,0
proj2 ,(default package) ,ExprNode ,FunCallFactor ,5 ,1 ,3
proj2 ,(default package) ,ExprNode ,getPow ,3 ,1 ,0
proj2 ,(default package) ,ExprNode ,getSymbol ,3 ,1 ,0
proj2 ,(default package) ,ExprNode ,getParaList ,3 ,1 ,0
proj2 ,(default package) ,ExprNode ,klone ,7 ,2 ,0
proj2 ,(default package) ,ExprNode ,ConstFactor ,3 ,1 ,1
proj2 ,(default package) ,ExprNode ,getValue ,3 ,1 ,0
proj2 ,(default package) ,ExprNode ,toString ,3 ,1 ,0
proj2 ,(default package) ,ExprNode ,klone ,3 ,1 ,0
proj2 ,(default package) ,ExprNode ,ExprFactor ,4 ,1 ,2
proj2 ,(default package) ,ExprNode ,getPow ,3 ,1 ,0
proj2 ,(default package) ,ExprNode ,getExpr ,3 ,1 ,0
proj2 ,(default package) ,ExprNode ,toString ,3 ,1 ,0
proj2 ,(default package) ,ExprNode ,klone ,3 ,1 ,0
proj2 ,(default package) ,ExprNode ,Term ,4 ,1 ,2
proj2 ,(default package) ,ExprNode ,getExprNodes ,3 ,1 ,0
proj2 ,(default package) ,ExprNode ,getPrefixOperator ,3 ,1 ,0
proj2 ,(default package) ,ExprNode ,toString ,3 ,1 ,0
proj2 ,(default package) ,ExprNode ,klone ,7 ,2 ,0
proj2 ,(default package) ,ExprNode ,Expr ,4 ,1 ,2
proj2 ,(default package) ,ExprNode ,getTerms ,3 ,1 ,0
proj2 ,(default package) ,ExprNode ,getPrefixOperators ,3 ,1 ,0
proj2 ,(default package) ,ExprNode ,toString ,3 ,1 ,0
proj2 ,(default package) ,ExprNode ,klone ,8 ,2 ,0
proj2 ,(default package) ,PowerFactor ,PowerFactor ,4 ,1 ,2
proj2 ,(default package) ,PowerFactor ,getPow ,3 ,1 ,0
proj2 ,(default package) ,PowerFactor ,getSymbol ,3 ,1 ,0
proj2 ,(default package) ,PowerFactor ,toString ,3 ,1 ,0
proj2 ,(default package) ,PowerFactor ,klone ,3 ,1 ,0
proj2 ,(default package) ,FunCallFactor ,FunCallFactor ,5 ,1 ,3
proj2 ,(default package) ,FunCallFactor ,getPow ,3 ,1 ,0
proj2 ,(default package) ,FunCallFactor ,getSymbol ,3 ,1 ,0
proj2 ,(default package) ,FunCallFactor ,getParaList ,3 ,1 ,0
proj2 ,(default package) ,FunCallFactor ,klone ,7 ,2 ,0
proj2 ,(default package) ,ConstFactor ,ConstFactor ,3 ,1 ,1
proj2 ,(default package) ,ConstFactor ,getValue ,3 ,1 ,0
proj2 ,(default package) ,ConstFactor ,toString ,3 ,1 ,0
proj2 ,(default package) ,ConstFactor ,klone ,3 ,1 ,0
proj2 ,(default package) ,ExprFactor ,ExprFactor ,4 ,1 ,2
proj2 ,(default package) ,ExprFactor ,getPow ,3 ,1 ,0
proj2 ,(default package) ,ExprFactor ,getExpr ,3 ,1 ,0
proj2 ,(default package) ,ExprFactor ,toString ,3 ,1 ,0
proj2 ,(default package) ,ExprFactor ,klone ,3 ,1 ,0
proj2 ,(default package) ,Term ,Term ,4 ,1 ,2
proj2 ,(default package) ,Term ,getExprNodes ,3 ,1 ,0
proj2 ,(default package) ,Term ,getPrefixOperator ,3 ,1 ,0
proj2 ,(default package) ,Term ,toString ,3 ,1 ,0
proj2 ,(default package) ,Term ,klone ,7 ,2 ,0
proj2 ,(default package) ,Expr ,Expr ,4 ,1 ,2
proj2 ,(default package) ,Expr ,getTerms ,3 ,1 ,0
proj2 ,(default package) ,Expr ,getPrefixOperators ,3 ,1 ,0
proj2 ,(default package) ,Expr ,toString ,3 ,1 ,0
proj2 ,(default package) ,Expr ,klone ,8 ,2 ,0
proj2 ,(default package) ,Main ,main ,18 ,2 ,1
proj2 ,(default package) ,Parser ,getName ,3 ,1 ,0
proj2 ,(default package) ,Parser ,getPos ,3 ,1 ,0
proj2 ,(default package) ,Parser ,getExpr ,3 ,1 ,0
proj2 ,(default package) ,Parser ,Parser ,8 ,1 ,1
proj2 ,(default package) ,Parser ,getParaList ,3 ,1 ,0
proj2 ,(default package) ,Parser ,parse ,4 ,1 ,0
proj2 ,(default package) ,Parser ,parseCustomFunction ,28 ,6 ,0
proj2 ,(default package) ,Parser ,expr ,19 ,4 ,0
proj2 ,(default package) ,Parser ,term ,26 ,6 ,0
proj2 ,(default package) ,Parser ,factor ,24 ,8 ,0
proj2 ,(default package) ,Parser ,funCallFactor ,34 ,8 ,0
proj2 ,(default package) ,Parser ,varFactor ,13 ,3 ,0
proj2 ,(default package) ,Parser ,number ,24 ,5 ,0
proj2 ,(default package) ,Parser ,constFactor ,4 ,1 ,0
proj2 ,(default package) ,Parser ,exprFactor ,20 ,4 ,0
proj2 ,(default package) ,Parser ,isAtEnd ,3 ,1 ,0
proj2 ,(default package) ,Parser ,peek ,3 ,1 ,0
proj2 ,(default package) ,Parser ,peek2 ,8 ,2 ,0
proj2 ,(default package) ,Parser ,advance ,3 ,1 ,0
proj2 ,(default package) ,Parser ,consume ,9 ,2 ,1
proj2 ,(default package) ,Simplifier ,simplify ,3 ,1 ,1
proj2 ,(default package) ,Simplifier ,simplifyExpr ,13 ,3 ,2
proj2 ,(default package) ,Simplifier ,simplifyTerm ,11 ,3 ,2
proj2 ,(default package) ,Simplifier ,simplifyFactor ,22 ,5 ,2
proj2 ,(default package) ,Simplifier ,applyPowerFactor ,21 ,3 ,2
proj2 ,(default package) ,Simplifier ,dispatchFunctions ,25 ,5 ,3
proj2 ,(default package) ,Simplifier ,dispatchTriangleFunctions ,4 ,1 ,3
proj2 ,(default package) ,Simplifier ,dispatchCos ,29 ,6 ,3
proj2 ,(default package) ,Simplifier ,dispatchSin ,29 ,6 ,3
proj2 ,(default package) ,Token ,Token ,5 ,1 ,3
proj2 ,(default package) ,Token ,getSymbol ,3 ,1 ,0
proj2 ,(default package) ,Token ,getNumber ,3 ,1 ,0
proj2 ,(default package) ,Token ,getType ,3 ,1 ,0
proj2 ,(default package) ,Token ,toString ,10 ,3 ,0
proj2 ,(default package) ,Tokenizer ,Tokenizer ,6 ,1 ,1
proj2 ,(default package) ,Tokenizer ,getTokens ,3 ,1 ,0
proj2 ,(default package) ,Tokenizer ,run ,55 ,14 ,0
proj2 ,(default package) ,Tokenizer ,identifier ,12 ,3 ,0
proj2 ,(default package) ,Tokenizer ,number ,17 ,3 ,0
proj2 ,(default package) ,Tokenizer ,peek ,8 ,2 ,0
proj2 ,(default package) ,Tokenizer ,peek2 ,8 ,2 ,0
proj2 ,(default package) ,Tokenizer ,advance ,3 ,1 ,0
proj2 ,(default package) ,Tokenizer ,isAtEnd ,3 ,1 ,0
proj2 ,util ,Klone ,klone ,0 ,1 ,0
Project Name ,Package Name ,Type Name ,NOF ,NOPF ,NOM ,NOPM ,LOC ,WMC ,NC ,DIT ,LCOM ,FANIN ,FANOUT
proj2 ,(default package) ,BasicFactor ,5 ,0 ,22 ,19 ,182 ,47 ,0 ,1 ,0.13636363636363635 ,0 ,0
proj2 ,(default package) ,BasicTerm ,2 ,0 ,14 ,14 ,114 ,29 ,0 ,1 ,0.14285714285714285 ,0 ,0
proj2 ,(default package) ,CustomFunction ,3 ,0 ,4 ,4 ,22 ,5 ,0 ,0 ,0.5 ,1 ,1
proj2 ,(default package) ,ExprNode ,12 ,0 ,30 ,30 ,142 ,33 ,0 ,1 ,0.16666666666666666 ,0 ,0
proj2 ,(default package) ,PowerFactor ,2 ,0 ,5 ,5 ,20 ,5 ,0 ,0 ,0.0 ,0 ,0
proj2 ,(default package) ,FunCallFactor ,3 ,0 ,5 ,5 ,26 ,6 ,0 ,0 ,0.0 ,0 ,0
proj2 ,(default package) ,ConstFactor ,1 ,0 ,4 ,4 ,15 ,4 ,0 ,0 ,0.0 ,0 ,0
proj2 ,(default package) ,ExprFactor ,2 ,0 ,5 ,5 ,20 ,5 ,0 ,0 ,0.0 ,0 ,0
proj2 ,(default package) ,Term ,2 ,0 ,5 ,5 ,24 ,6 ,0 ,0 ,0.0 ,0 ,0
proj2 ,(default package) ,Expr ,2 ,0 ,5 ,5 ,25 ,6 ,0 ,0 ,0.0 ,0 ,0
proj2 ,(default package) ,Main ,0 ,0 ,1 ,1 ,20 ,2 ,0 ,0 ,-1.0 ,0 ,0
proj2 ,(default package) ,Parser ,6 ,0 ,20 ,7 ,250 ,58 ,0 ,0 ,0.15 ,0 ,0
proj2 ,(default package) ,Simplifier ,0 ,0 ,9 ,2 ,159 ,33 ,0 ,0 ,-1.0 ,0 ,0
proj2 ,(default package) ,Token ,3 ,0 ,5 ,5 ,29 ,7 ,0 ,0 ,0.0 ,0 ,0
proj2 ,(default package) ,Tokenizer ,4 ,0 ,9 ,3 ,121 ,28 ,0 ,0 ,0.0 ,0 ,0
proj2 ,util ,Klone ,0 ,0 ,1 ,0 ,3 ,1 ,3 ,0 ,-1.0 ,0 ,0
看起来数据上方法的复杂度不高,但是实际上是用IDEA强行抽取方法降低的圈复杂度和方法长度,其实代码结构已经很乱了。
Bug
发现了两个bug(我感觉可能有更多没发现的)
- 数据表示不统一,比如3*x可能表示为
Term(3,Factor(1,1))
或者Term(1,Factor(3,1))
或者之类的情况,化简时情况没考虑完整(高复杂度的代码导致完整考虑非常困难) - 输出部分每一个层次考虑了不属于本层次的东西,比如
Term
在考虑输出Factor
的细节,不符合封装的思想,导致考虑不充分出现Bug。
然后加了一堆特判改Bug。
代码更加没眼看了,只能重构。
第三次作业
概述
第三次作业进行了重构,由于词法分析和语法分析部分与简化部分解耦,可以不用修改,所以工作量尚可(架构崩了,但没完全崩)。
用完整的层次结构建立了表达式的抽象,并在此之上进行化简。(代码甚至相比第二次作业还有所简化)
UML
分析
对主要化简部分进行了重构,将ArrayList<BasicTerm>
封装成了BasicExpr
,并基本上让各个类各司其职。但是感觉仍然有优化空间,比如Basicxx
类有mergeIn
,simplify
,canMerge
等公共方法,可以抽取一个接口。Simplifier
类仍然是一堆静态方法,可以考虑用访问者模式重构。
度量值
Project Name ,Package Name ,Type Name ,MethodName ,LOC ,CC ,PC
proj3 ,(default package) ,CustomFunction ,CustomFunction ,4 ,1 ,2
proj3 ,(default package) ,CustomFunction ,registerFunction ,3 ,1 ,2
proj3 ,(default package) ,CustomFunction ,getFunction ,3 ,1 ,1
proj3 ,(default package) ,CustomFunction ,eval ,7 ,2 ,1
proj3 ,(default package) ,ExprNode ,wrapNode ,10 ,1 ,1
proj3 ,(default package) ,ExprNode ,PowerFactor ,4 ,1 ,2
proj3 ,(default package) ,ExprNode ,getPow ,3 ,1 ,0
proj3 ,(default package) ,ExprNode ,getSymbol ,3 ,1 ,0
proj3 ,(default package) ,ExprNode ,toString ,3 ,1 ,0
proj3 ,(default package) ,ExprNode ,klone ,3 ,1 ,0
proj3 ,(default package) ,ExprNode ,FunCallFactor ,5 ,1 ,3
proj3 ,(default package) ,ExprNode ,getPow ,3 ,1 ,0
proj3 ,(default package) ,ExprNode ,getSymbol ,3 ,1 ,0
proj3 ,(default package) ,ExprNode ,getParaList ,3 ,1 ,0
proj3 ,(default package) ,ExprNode ,klone ,7 ,2 ,0
proj3 ,(default package) ,ExprNode ,ConstFactor ,3 ,1 ,1
proj3 ,(default package) ,ExprNode ,getValue ,3 ,1 ,0
proj3 ,(default package) ,ExprNode ,toString ,3 ,1 ,0
proj3 ,(default package) ,ExprNode ,klone ,3 ,1 ,0
proj3 ,(default package) ,ExprNode ,ExprFactor ,4 ,1 ,2
proj3 ,(default package) ,ExprNode ,getPow ,3 ,1 ,0
proj3 ,(default package) ,ExprNode ,getExpr ,3 ,1 ,0
proj3 ,(default package) ,ExprNode ,toString ,3 ,1 ,0
proj3 ,(default package) ,ExprNode ,klone ,3 ,1 ,0
proj3 ,(default package) ,ExprNode ,Term ,4 ,1 ,2
proj3 ,(default package) ,ExprNode ,getExprNodes ,3 ,1 ,0
proj3 ,(default package) ,ExprNode ,getPrefixOperator ,3 ,1 ,0
proj3 ,(default package) ,ExprNode ,toString ,3 ,1 ,0
proj3 ,(default package) ,ExprNode ,klone ,7 ,2 ,0
proj3 ,(default package) ,ExprNode ,Expr ,4 ,1 ,2
proj3 ,(default package) ,ExprNode ,getTerms ,3 ,1 ,0
proj3 ,(default package) ,ExprNode ,getPrefixOperators ,3 ,1 ,0
proj3 ,(default package) ,ExprNode ,toString ,3 ,1 ,0
proj3 ,(default package) ,ExprNode ,klone ,8 ,2 ,0
proj3 ,(default package) ,PowerFactor ,PowerFactor ,4 ,1 ,2
proj3 ,(default package) ,PowerFactor ,getPow ,3 ,1 ,0
proj3 ,(default package) ,PowerFactor ,getSymbol ,3 ,1 ,0
proj3 ,(default package) ,PowerFactor ,toString ,3 ,1 ,0
proj3 ,(default package) ,PowerFactor ,klone ,3 ,1 ,0
proj3 ,(default package) ,FunCallFactor ,FunCallFactor ,5 ,1 ,3
proj3 ,(default package) ,FunCallFactor ,getPow ,3 ,1 ,0
proj3 ,(default package) ,FunCallFactor ,getSymbol ,3 ,1 ,0
proj3 ,(default package) ,FunCallFactor ,getParaList ,3 ,1 ,0
proj3 ,(default package) ,FunCallFactor ,klone ,7 ,2 ,0
proj3 ,(default package) ,ConstFactor ,ConstFactor ,3 ,1 ,1
proj3 ,(default package) ,ConstFactor ,getValue ,3 ,1 ,0
proj3 ,(default package) ,ConstFactor ,toString ,3 ,1 ,0
proj3 ,(default package) ,ConstFactor ,klone ,3 ,1 ,0
proj3 ,(default package) ,ExprFactor ,ExprFactor ,4 ,1 ,2
proj3 ,(default package) ,ExprFactor ,getPow ,3 ,1 ,0
proj3 ,(default package) ,ExprFactor ,getExpr ,3 ,1 ,0
proj3 ,(default package) ,ExprFactor ,toString ,3 ,1 ,0
proj3 ,(default package) ,ExprFactor ,klone ,3 ,1 ,0
proj3 ,(default package) ,Term ,Term ,4 ,1 ,2
proj3 ,(default package) ,Term ,getExprNodes ,3 ,1 ,0
proj3 ,(default package) ,Term ,getPrefixOperator ,3 ,1 ,0
proj3 ,(default package) ,Term ,toString ,3 ,1 ,0
proj3 ,(default package) ,Term ,klone ,7 ,2 ,0
proj3 ,(default package) ,Expr ,Expr ,4 ,1 ,2
proj3 ,(default package) ,Expr ,getTerms ,3 ,1 ,0
proj3 ,(default package) ,Expr ,getPrefixOperators ,3 ,1 ,0
proj3 ,(default package) ,Expr ,toString ,3 ,1 ,0
proj3 ,(default package) ,Expr ,klone ,8 ,2 ,0
proj3 ,(default package) ,Main ,main ,18 ,2 ,1
proj3 ,(default package) ,Parser ,getName ,3 ,1 ,0
proj3 ,(default package) ,Parser ,getPos ,3 ,1 ,0
proj3 ,(default package) ,Parser ,getExpr ,3 ,1 ,0
proj3 ,(default package) ,Parser ,Parser ,8 ,1 ,1
proj3 ,(default package) ,Parser ,getParaList ,3 ,1 ,0
proj3 ,(default package) ,Parser ,parse ,4 ,1 ,0
proj3 ,(default package) ,Parser ,parseCustomFunction ,28 ,6 ,0
proj3 ,(default package) ,Parser ,expr ,19 ,4 ,0
proj3 ,(default package) ,Parser ,term ,26 ,6 ,0
proj3 ,(default package) ,Parser ,factor ,24 ,8 ,0
proj3 ,(default package) ,Parser ,funCallFactor ,34 ,8 ,0
proj3 ,(default package) ,Parser ,varFactor ,13 ,3 ,0
proj3 ,(default package) ,Parser ,number ,24 ,5 ,0
proj3 ,(default package) ,Parser ,constFactor ,4 ,1 ,0
proj3 ,(default package) ,Parser ,exprFactor ,20 ,4 ,0
proj3 ,(default package) ,Parser ,isAtEnd ,3 ,1 ,0
proj3 ,(default package) ,Parser ,peek ,3 ,1 ,0
proj3 ,(default package) ,Parser ,peek2 ,8 ,2 ,0
proj3 ,(default package) ,Parser ,advance ,3 ,1 ,0
proj3 ,(default package) ,Parser ,consume ,9 ,2 ,1
proj3 ,(default package) ,Simplifier ,simplify ,5 ,1 ,1
proj3 ,(default package) ,Simplifier ,simplifyExpr ,13 ,3 ,2
proj3 ,(default package) ,Simplifier ,simplifyTerm ,11 ,3 ,2
proj3 ,(default package) ,Simplifier ,simplifyFactor ,21 ,5 ,2
proj3 ,(default package) ,Simplifier ,applyPowerFactor ,17 ,3 ,2
proj3 ,(default package) ,Simplifier ,dispatchFunctions ,28 ,6 ,3
proj3 ,(default package) ,Simplifier ,dispatchTriangleFunctions ,10 ,2 ,3
proj3 ,(default package) ,Token ,Token ,5 ,1 ,3
proj3 ,(default package) ,Token ,getSymbol ,3 ,1 ,0
proj3 ,(default package) ,Token ,getNumber ,3 ,1 ,0
proj3 ,(default package) ,Token ,getType ,3 ,1 ,0
proj3 ,(default package) ,Token ,toString ,10 ,3 ,0
proj3 ,(default package) ,Tokenizer ,Tokenizer ,6 ,1 ,1
proj3 ,(default package) ,Tokenizer ,getTokens ,3 ,1 ,0
proj3 ,(default package) ,Tokenizer ,run ,55 ,14 ,0
proj3 ,(default package) ,Tokenizer ,identifier ,12 ,3 ,0
proj3 ,(default package) ,Tokenizer ,number ,17 ,3 ,0
proj3 ,(default package) ,Tokenizer ,peek ,8 ,2 ,0
proj3 ,(default package) ,Tokenizer ,peek2 ,8 ,2 ,0
proj3 ,(default package) ,Tokenizer ,advance ,3 ,1 ,0
proj3 ,(default package) ,Tokenizer ,isAtEnd ,3 ,1 ,0
proj3 ,util ,Klone ,klone ,0 ,1 ,0
proj3 ,values ,BasicExpr ,BasicExpr ,3 ,1 ,1
proj3 ,values ,BasicExpr ,BasicExpr ,3 ,1 ,0
proj3 ,values ,BasicExpr ,mul ,9 ,3 ,1
proj3 ,values ,BasicExpr ,negate ,6 ,2 ,0
proj3 ,values ,BasicExpr ,add ,4 ,1 ,1
proj3 ,values ,BasicExpr ,add ,4 ,1 ,1
proj3 ,values ,BasicExpr ,simplify ,18 ,5 ,0
proj3 ,values ,BasicExpr ,unwrap ,11 ,3 ,0
proj3 ,values ,BasicExpr ,toString ,14 ,4 ,0
proj3 ,values ,BasicExpr ,compareTo ,14 ,4 ,1
proj3 ,values ,BasicExpr ,klone ,7 ,2 ,0
proj3 ,values ,BasicFactor ,BasicFactor ,6 ,1 ,4
proj3 ,values ,BasicFactor ,createX ,3 ,1 ,2
proj3 ,values ,BasicFactor ,createCos ,3 ,1 ,3
proj3 ,values ,BasicFactor ,createSin ,3 ,1 ,3
proj3 ,values ,BasicFactor ,createTriangle ,11 ,3 ,4
proj3 ,values ,BasicFactor ,canMerge ,3 ,1 ,2
proj3 ,values ,BasicFactor ,getFactorString ,25 ,7 ,3
proj3 ,values ,BasicFactor ,simplify ,22 ,6 ,0
proj3 ,values ,BasicFactor ,mergeIn ,4 ,1 ,1
proj3 ,values ,BasicFactor ,wrap ,5 ,1 ,0
proj3 ,values ,BasicFactor ,isOne ,3 ,1 ,0
proj3 ,values ,BasicFactor ,isZero ,3 ,1 ,0
proj3 ,values ,BasicFactor ,klone ,3 ,1 ,0
proj3 ,values ,BasicFactor ,getFactorType ,3 ,1 ,0
proj3 ,values ,BasicFactor ,getFac ,3 ,1 ,0
proj3 ,values ,BasicFactor ,setFac ,3 ,1 ,1
proj3 ,values ,BasicFactor ,getIdx ,3 ,1 ,0
proj3 ,values ,BasicFactor ,setIdx ,3 ,1 ,1
proj3 ,values ,BasicFactor ,compareTo ,23 ,5 ,1
proj3 ,values ,BasicFactor ,toString ,28 ,7 ,0
proj3 ,values ,BasicTerm ,BasicTerm ,4 ,1 ,2
proj3 ,values ,BasicTerm ,BasicTerm ,5 ,1 ,0
proj3 ,values ,BasicTerm ,canMerge ,14 ,4 ,2
proj3 ,values ,BasicTerm ,getBasicFactors ,3 ,1 ,0
proj3 ,values ,BasicTerm ,getFac ,3 ,1 ,0
proj3 ,values ,BasicTerm ,setFac ,3 ,1 ,1
proj3 ,values ,BasicTerm ,klone ,4 ,1 ,0
proj3 ,values ,BasicTerm ,mul ,6 ,1 ,1
proj3 ,values ,BasicTerm ,mul ,4 ,1 ,1
proj3 ,values ,BasicTerm ,add ,3 ,1 ,1
proj3 ,values ,BasicTerm ,negate ,3 ,1 ,0
proj3 ,values ,BasicTerm ,extractFactor ,4 ,1 ,0
proj3 ,values ,BasicTerm ,simplify ,20 ,5 ,0
proj3 ,values ,BasicTerm ,mergeIn ,3 ,1 ,1
proj3 ,values ,BasicTerm ,wrap ,5 ,1 ,0
proj3 ,values ,BasicTerm ,unwrap ,13 ,3 ,0
proj3 ,values ,BasicTerm ,toString ,24 ,6 ,0
proj3 ,values ,BasicTerm ,compareTo ,17 ,5 ,1
Project Name ,Package Name ,Type Name ,NOF ,NOPF ,NOM ,NOPM ,LOC ,WMC ,NC ,DIT ,LCOM ,FANIN ,FANOUT
proj3 ,(default package) ,CustomFunction ,3 ,0 ,4 ,4 ,22 ,5 ,0 ,0 ,0.5 ,1 ,1
proj3 ,(default package) ,ExprNode ,12 ,0 ,30 ,30 ,142 ,33 ,0 ,1 ,0.16666666666666666 ,0 ,0
proj3 ,(default package) ,PowerFactor ,2 ,0 ,5 ,5 ,20 ,5 ,0 ,0 ,0.0 ,0 ,0
proj3 ,(default package) ,FunCallFactor ,3 ,0 ,5 ,5 ,26 ,6 ,0 ,0 ,0.0 ,0 ,0
proj3 ,(default package) ,ConstFactor ,1 ,0 ,4 ,4 ,15 ,4 ,0 ,0 ,0.0 ,0 ,0
proj3 ,(default package) ,ExprFactor ,2 ,0 ,5 ,5 ,20 ,5 ,0 ,0 ,0.0 ,0 ,0
proj3 ,(default package) ,Term ,2 ,0 ,5 ,5 ,24 ,6 ,0 ,0 ,0.0 ,0 ,0
proj3 ,(default package) ,Expr ,2 ,0 ,5 ,5 ,25 ,6 ,0 ,0 ,0.0 ,0 ,0
proj3 ,(default package) ,Main ,0 ,0 ,1 ,1 ,20 ,2 ,0 ,0 ,-1.0 ,0 ,0
proj3 ,(default package) ,Parser ,6 ,0 ,20 ,7 ,250 ,58 ,0 ,0 ,0.15 ,0 ,0
proj3 ,(default package) ,Simplifier ,0 ,0 ,7 ,2 ,107 ,23 ,0 ,0 ,-1.0 ,0 ,3
proj3 ,(default package) ,Token ,3 ,0 ,5 ,5 ,29 ,7 ,0 ,0 ,0.0 ,0 ,0
proj3 ,(default package) ,Tokenizer ,4 ,0 ,9 ,3 ,121 ,28 ,0 ,0 ,0.0 ,0 ,0
proj3 ,util ,Klone ,0 ,0 ,1 ,0 ,3 ,1 ,4 ,0 ,-1.0 ,0 ,0
proj3 ,values ,BasicExpr ,1 ,0 ,11 ,11 ,96 ,27 ,0 ,1 ,0.0 ,3 ,2
proj3 ,values ,BasicFactor ,4 ,0 ,20 ,19 ,167 ,43 ,0 ,1 ,0.0 ,3 ,3
proj3 ,values ,BasicTerm ,2 ,0 ,18 ,18 ,142 ,36 ,0 ,1 ,0.0 ,4 ,2
简化部分的复杂度被分解,圈复杂度降低,可以看到BasicTerm
BasicFactor
BasicExpr
的内聚缺乏度为0.0,度量值分析得到封装是有效的。
Bug
重构很有效,不仅课下debug时间要少于第二次作业。而且强测和互测都没有发现Bug(自动生成数据测试在强测前发现了一个和指导书理解有关的bug,很好解决,即sum下界大于上界)。
代码架构真的很重要。
思考
简化表达式算法
我的算法只能在同一层次进行化简,对cos(x)**2+sin(x)**2
的处理会非常复杂,也没有想到很好的方法。
不可变数据结构与所有权
在C++等手动管理内存的语言中,为了减少内存泄漏的风险,需要用到所有权的概念,比如方法的意图是拿走这个对象还是保证只获取这个对象的引用。这样来保证对象被释放且只被释放一次。
虽然Java有GC不需要我们手动管理内存,但是运用所有权可以减少潜在的Bug。比如我的一段存在Bug的Java代码的等价Rust代码长这样。(已简化)
//impl BasicTerm
fn unwrap(&mut self) -> BasicFactor{
if self.basicFactors.len() == 1{
//判断能不能拆一层把只有一个因子的项拆成因子
...
if canUnwrap {
return basicFactors[0];
}
}
}
因为Rust的所有权模型,这无法通过编译,因为我们不能把BasicTerm
中的BasicFactor
移出去,因为我们只有它的可变引用。
Java不阻止这种行为,但是Bug不在编译期体现就在运行期体现,这样移出去的BasicFactor
仍然指向原来BasicTerm
里的BasicFactor
,如果我们把它当作两个对象分别修改,就会出现难以定位的问题(我就被这卡了好久)。
解决方法是复制一份再操作,或者使用不可变对象,想修改只能复制(注意深复制)
hack策略
如果是手工构造数据,可能数据不在于长,而在于准确命中可能的边界条件。
比如
cos(sin(cos(sin(0))))
-+ - 0
等。长的数据可能是同质化的,其实效果和短数据一样。
同时,数据也应该有针对性,比如第二个数据是我在阅读某位同学的代码时发现他对符号的处理让我迷惑(看不懂),于是整了这么一个数据,然后真中了。。
当然,如果能够自己写评测机当然更好(但是会增加工作量)。