其他分享
首页 > 其他分享> > BUAA OO Unit1 —— Expression Parser

BUAA OO Unit1 —— Expression Parser

作者:互联网

BUAA OO Unit1 —— Expression Parser

by Monument_Valley

0. 写在正文前

本篇博客是对笔者在北航2022年春季《面向对象设计与构造》课程第一单元的三次作业的总结。

本单元的主要任务为通过程序对一个表达式解构进行建模,完成对多余括号的展开。在迭代开发时,增加支持的因子种类,并将括号层数改为无限嵌套括号。

这篇博客是本人博客处女作,望老师、助教、本校与友校的同学们多多指教(求轻虐)

1. Homework 1

1.1 架构分析

第一次作业的主任务是对含有单层括号与单变量的表达式(其中运算符只有+(加), -(减), *(乘), **(乘方))进行解析并进行化简。

在分析之前,我们给出对一个表达式的架构:我们知道,一个表达式由多个项通过加减号连接而成,而一个项由多个因子通过乘号进行连接。而在这次作业中,我们的因子只有常数因子,表达式因子(将一个表达式在外套上一层括号)与幂函数因子(即变量x的幂)构成,而由于没有嵌套括号,表达式因子在括号内的部分(即表达式)是不会出现括号的,这就给我们通过正则表达式建构一个表达式的结构提供了可能。

本次作业的类图如下:

乍一看好像类有许多(其实是我写的废话太多),不过每个类需要完成的任务还是比较清晰的。为了看懂这张图,你需要先知道为了输出化简表达式我们都需要干些什么。本次作业中程序需要完成的几个基本任务如下:

  1. 预处理表达式,使其方便正则表达式解析。如:去除空白字符,将乘方符号替换为^,合并多余的加减号等。
  2. 使用正则表达式进行递归下降解析(表达式 --> 项 --> 因子),对不同部分分别用类建立对象。
  3. 使用Add/Multiple类对各个对象进行计算,展开所有括号。
  4. 对表达式建立HashMap,合并所有的项。在本次作业中,HashMap的key为变量x的幂次(当次数为0时,存储的就是常数项),value为各个幂次的幂函数前的常数因子。
  5. 使用Print类,根据表达式的HashMap的值对化简后的表达式进行输出。
  6. 根据评测机的性能要求对表达式进行鸡贼化简hhhhh

现在回过头来看这个架构,感觉类之间的关系太松散了。。。功能也不是那么明确。

1.2 复杂度分析

类复杂度如下:

class OCavg OCmax WMC
arithmetic.Add 6.0 6.0 6.0
arithmetic.Multiple 6.0 6.0 6.0
com.oocourse.spec1.ExprInput 2.75 4.0 11.0
com.oocourse.spec1.ExprInputMode 1.0 1.0 1.0
expr.expression.Expression 1.3333333333333333 3.0 12.0
expr.factor.ConstantFactor 6.0 6.0 6.0
expr.factor.ExpFactor 10.0 10.0 10.0
expr.factor.ExprFactor 4.0 13.0 16.0
expr.factor.Factor 1.0 1.0 4.0
expr.term.Term 1.7 5.0 17.0
Main 2.0 2.0 2.0
operation.Parser 1.1111111111111112 2.0 10.0
operation.Print 7.0 19.0 28.0
setting.Setting 1.0 1.0 1.0
Total 130.0
Average 2.549019607843137 5.642857142857143 9.285714285714286

方法复杂度如下:

method CogC ev(G) iv(G) v(G)
operation.Print.addTerm(StringBuilder, HashMap, int) 23.0 1.0 10.0 16.0
expr.factor.ExprFactor.ExprFactor(String, String, String, String) 20.0 1.0 13.0 15.0
expr.factor.ExpFactor.ExpFactor(String, String, String) 18.0 1.0 10.0 12.0
arithmetic.Add.add(HashMap, HashMap) 10.0 1.0 9.0 9.0
expr.factor.ConstantFactor.ConstantFactor(String, String, String) 8.0 1.0 6.0 7.0
arithmetic.Multiple.multiple(HashMap, HashMap) 12.0 1.0 6.0 6.0
expr.term.Term.parseTerm() 5.0 1.0 5.0 5.0
com.oocourse.spec1.ExprInput.parse() 6.0 1.0 4.0 4.0
expr.term.Term.calculateValue() 5.0 1.0 4.0 4.0
operation.Print.printValue(HashMap) 4.0 1.0 4.0 4.0
com.oocourse.spec1.ExprInput.ExprInput(ExprInputMode) 3.0 1.0 3.0 3.0
expr.expression.Expression.calculateValue() 2.0 1.0 3.0 3.0
operation.Print.findPositiveTerm(HashMap) 3.0 3.0 2.0 3.0
Main.main(String[]) 1.0 1.0 2.0 2.0
com.oocourse.spec1.ExprInput.getCount() 1.0 1.0 2.0 2.0
com.oocourse.spec1.ExprInput.readLine() 1.0 1.0 2.0 2.0
expr.expression.Expression.parseExpression() 1.0 1.0 2.0 2.0
operation.Parser.replaceExtraOperation(String) 1.0 1.0 2.0 2.0
operation.Print.removeRedundantSign(String) 1.0 1.0 2.0 2.0
com.oocourse.spec1.ExprInputMode.ExprInputMode() 0.0 1.0 1.0 1.0
expr.expression.Expression.Expression(String) 0.0 1.0 1.0 1.0
expr.expression.Expression.getInput() 0.0 1.0 1.0 1.0
expr.expression.Expression.getTerms() 0.0 1.0 1.0 1.0
expr.expression.Expression.getValue() 0.0 1.0 1.0 1.0
expr.expression.Expression.setInput(String) 0.0 1.0 1.0 1.0
expr.expression.Expression.setTerms(ArrayList) 0.0 1.0 1.0 1.0
expr.expression.Expression.setValue(HashMap) 0.0 1.0 1.0 1.0
expr.factor.ExprFactor.getExprExpr() 0.0 1.0 1.0 1.0
expr.factor.ExprFactor.getExprExprValue() 0.0 1.0 1.0 1.0
expr.factor.ExprFactor.setExprExpr(String) 0.0 1.0 1.0 1.0
expr.factor.Factor.getBigValue() 0.0 1.0 1.0 1.0
expr.factor.Factor.getValue() 0.0 1.0 1.0 1.0
expr.factor.Factor.setBigValue(BigInteger) 0.0 1.0 1.0 1.0
expr.factor.Factor.setValue(HashMap) 0.0 1.0 1.0 1.0
expr.term.Term.Term(String) 0.0 1.0 1.0 1.0
expr.term.Term.getFactor() 0.0 1.0 1.0 1.0
expr.term.Term.getFactors() 0.0 1.0 1.0 1.0
expr.term.Term.getInput() 0.0 1.0 1.0 1.0
expr.term.Term.getValue() 0.0 1.0 1.0 1.0
expr.term.Term.setFactors(ArrayList) 0.0 1.0 1.0 1.0
expr.term.Term.setInput(String) 0.0 1.0 1.0 1.0
expr.term.Term.setValue(HashMap) 0.0 1.0 1.0 1.0
operation.Parser.Parser(String) 0.0 1.0 1.0 1.0
operation.Parser.getPreprocessedString() 0.0 1.0 1.0 1.0
operation.Parser.getValue() 0.0 1.0 1.0 1.0
operation.Parser.parseExpr() 0.0 1.0 1.0 1.0
operation.Parser.removeBlank(String) 0.0 1.0 1.0 1.0
operation.Parser.replacePowChar(String) 0.0 1.0 1.0 1.0
operation.Parser.setPreprocessedString(String) 0.0 1.0 1.0 1.0
operation.Parser.setValue(HashMap) 0.0 1.0 1.0 1.0
setting.Setting.getMaxIndex() 0.0 1.0 1.0 1.0
Total 125.0 53.0 123.0 135.0
Average 2.450980392156863 1.0392156862745099 2.411764705882353 2.6470588235294117

可以看到,这回程序的复杂度偏高,原因在于我的程序在识别表达式/项/因子的时候,识别与生成对象的工作几乎全部堆到对应类的构造函数之中,由于没有对方法进行很好的设计,一个构造函数内耦合了太多的功能,致使其臃肿不堪,写成了面向过程设计,这与本课程的初衷不符。

还有一个原因是这回的程序采用正则表达式进行解析,这就使得我需要在程序内提前写好正则表达式以进行调用,这也造成解析表达式的类与其它相关的方法复杂度过高。

1.3 评测成绩

强测AC,性能分100,互测无bug。

2. Homework 2

这次作业是笔者本单元最痛苦的一次作业,对程序进行了彻底重构。

2.1 架构分析

这次作业新增了对三角函数因子(sincos),自定义函数因子(最多支持3种自定义函数因子)与求和函数因子的支持。其中,三角函数内的因子一定是一个幂函数因子。

由于这次新增了函数,而函数的变量可以为表达式因子(Homework 1已经提到,表达式因子与表达式的区别在于表达式因子的最外层需要套上一层括号,这时将表达式因子视为一个因子,而非一个表达式),这就意味着原始输入的表达式需要出现嵌套括号。由于对第一次作业架构的依赖,笔者起初想继续通过正则表达式解析整个表达式(只要括号有限,同时恰当使用贪婪匹配,那么使用正则表达式解析也不是不可以)。

在完成这个没有为捕获组命名就有将近900个字符的正则表达式后,笔者预感到第三次作业极大概率会出现无限嵌套括号表达式(正则表达式已经被证明无法处理无限嵌套括号)。由此,以正则表达式为核心的程序设计架构是迟早要被淘汰的,因此,笔者放弃了这种架构,转而尝试对程序进行递归下降解析。

这回这个类图有点大,但我先贴出来,便于之后的解释:

程序需要完成的基本任务与第一次作业没什么太大差别(废话,否则为什么叫迭代式开发),但我写得更抽象一点:

  1. 如果有自定义函数,解析自定义函数。
  2. 预处理表达式,使其方便正则表达式解析。
  3. 递归下降解析表达式,对不同的子部分分别用类建立对象,将其存储在父对象的ArrayList中。
  4. 使用Add/Multiple类对表达式下的各个对象进行计算,合并这些对象的值,直至合并到最外面的表达式。
  5. 对表达式进行化简。
  6. 输出表达式。
  7. 根据评测机的性能要求对表达式进行鸡贼化简hhhhh

第一步中直接识别形式参量,将其整理为一个ArrayList,同时识别自定义函数表达式,将二者存储到FormulaPattern类中的对象,一次作为模版

第二步没什么可说的,把空格、多余加减号和乘方符号替换即可。

第三步实际是一个自动状态机,通过解析括号以外的加减号与乘号就可以将字符串进行切割,得到解析因子类型所需的字符串原材料。

在这个时候,我们发现,第一步到第三步所完成的实际是字符串的处理工作!

为此,我们利用工厂模式,将自定义函数的识别工作交给FormulaFactory完成,并将之前得到的FormulaPattern对象作为模版存入到FormulaFactory中;

字符串替换(我愿将之称为清洗字符串)交给StringFactory完成;

表达式/项字符串分割工作分别交给TermFactoryFactorFactory完成;

因子的识别交给FactorFactory完成。

可以看到,我写了个枚举型FactorType,它的作用在于直接命名各因子,使程序更加直观,同时,为常量、变量与三角函数的关系排个序,方便之后的化简。

第四步的解释需要借用BUAAOO课程组的ppt插图:

结合图来看,根据我们已掌握的情况:

  1. 表达式 --> 项 --> 因子的结构是确定的,而由于多项式因子,求和函数因子与自定义函数因子的存在,有些因子的值实际上是一个表达式的值。
  2. 求和函数是一个将变量i替换为区间内的数,将其带入到表达式求值的过程;自定义函数是一个将表达式内的形式变量(x,y,z)替换为实际变量并计算表达式的值的过程。

表达式、项、因子在某种程度上是一个环状的关系,当因子为表达式因子、求和函数因子、自定义函数因子时,这些因子的值是一种表达式的值;当因子为变量因子,常量因子,幂函数因子与三角函数因子时,因子的值与第一次作业相似。因此,只有在因子为常数因子、变量因子与三角函数因子时,这个圈才会破开。

这种分析给了我们递归下降的思路:表达式分解到因子比较容易,如果可以打通因子值与表达式值之间的计算,那么就可以解决多项式因子、求和函数因子与自定义函数因子的分析问题!此外,如果可以完成这一步,无限嵌套括号的问题也就迎刃而解了!

寻找计算方法的前提是要找到一个合适的存储办法。计算上的统一需要以存储形式的统一为前提。那我们该如何统一表达式、项与因子的存储呢?

这个问题其实很简单。别忘了这个概念:

“因子是只有一个因子的项,因子是某个只有一个项的表达式,而其中的这个项只有一个因子。” ——Monument Valley

在“伟人”的指导下,我们有了这样的一个表达式值的存储结构:ExpressionValue: HashMap(TermValue, BigInteger)

其中:TermValue: ArrayList(FactorValue),BigInteger表示表达式中的一个项的常数因子的值,

FactorValue包含3个内容:Factor的类型FactorType,一个用来表示三角函数因子内部表达式的字符串(如果FactorType不是SINCOS,则这项为空字符串),以及因子的幂次。

对于项/表达式,我们可获得如下的通式:\(\sum ax^b·\prod sin^\alpha(f(x))·\prod cos^\beta(g(x))\)

对于此式,f(x)和g(x)为存储的三角函数内表达式的字符串,\(b\), \(\alpha\) 与 \(\beta\) 为因子的幂次,连乘号通过向TermValue的ArrayList添加因子来体现,求和号通过HashMap的键值对数目来体现。

统一表达式与因子的表示方式后,我们就可以定义它们的加法与乘法了!

此外,对于求和因子与自定义因子,其本质工作是一种在表达式模型基础上的替换工作。有了统一因子与表达式的工作,我可以直接在需要替换进表达式的变量外面加上一层括号,然后以字符串替换的方式替换的表达式中。毕竟,表达式因子和普通因子在值的表达形式上是统一的,那么,对一个值加上一层括号,也不会影响它的值。

举个例子:假设定义f(x, y) = y ** 2 * x,求f(x, x ** 3),此时,若加上这层括号,值就变成了(x**3)**2*(x),进而可以变成x**7,那要是不加括号呢?最后面的那个x不加括号还能理解,但x**3**2可是违背了指导书里的形式化表达定义,这又该怎么处理呢?显然,针对x**3**2这个字符串,这时无法解析。

这就完成了第四步的工作。

至于第五步,由于时间有限,我只完成了sin(0)与cos(0)的化简,以及合并同类项(这个其实是在第四步运算的时候完成的),二倍角与\(sin^2(x) + cos^2(x) = 1\)等化简并没有完成。

第六步中,只需按照ExpressionValue的存储格式按序输出即可。

2.2 复杂度分析

类复杂度:

class OCavg OCmax WMC
factory.FactorFactory 11.333333333333334 14.0 34.0
arithmetic.Add 7.0 7.0 7.0
factory.TermFactory 7.0 7.0 7.0
factory.StringFactory 6.0 27.0 48.0
arithmetic.Multiple 5.5 7.0 11.0
factory.FormulaFactory 3.0 7.0 9.0
Main 2.0 2.0 2.0
valueobject.TermValue 2.0 5.0 8.0
expr.factor.PowFactor 1.5714285714285714 4.0 11.0
valueobject.FactorValue 1.5555555555555556 6.0 14.0
expr.factor.formula.FormulaFactor 1.3333333333333333 4.0 12.0
expr.factor.ConstantFactor 1.2857142857142858 3.0 9.0
valueobject.ExpressionValue 1.2857142857142858 3.0 9.0
expr.factor.formula.SumFactor 1.25 4.0 15.0
expr.expression.Expression 1.2222222222222223 2.0 11.0
expr.term.Term 1.1111111111111112 2.0 10.0
expr.factor.TriangleFactor 1.1 2.0 11.0
expr.factor.ExprFactor 1.0 1.0 3.0
expr.factor.Factor 1.0 1.0 5.0
expr.factor.XFactor 1.0 1.0 2.0
expr.factor.formula.FormulaPattern 1.0 1.0 5.0
expr.factor.FactorType 0.0
Total 243.0
Average 2.076923076923077 5.238095238095238 11.045454545454545

方法复杂度:

method CogC ev(G) iv(G) v(G)
factory.StringFactory.factorToString(FactorValue, boolean) 59.0 23.0 7.0 23.0
factory.StringFactory.exprToString(ExpressionValue) 16.0 3.0 9.0 10.0
arithmetic.Multiple.mul(TermValue, TermValue) 14.0 1.0 8.0 8.0
factory.TermFactory.splitTerms(String) 14.0 1.0 7.0 10.0
arithmetic.Add.add(ExpressionValue, ExpressionValue) 13.0 4.0 7.0 7.0
factory.FactorFactory.judgeFactorType(String) 12.0 11.0 12.0 12.0
factory.FactorFactory.splitFactors(String) 12.0 1.0 9.0 9.0
factory.StringFactory.termToString(TermValue, BigInteger) 11.0 2.0 11.0 12.0
factory.FormulaFactory.splitByCommon(String) 10.0 1.0 7.0 7.0
expr.factor.formula.SumFactor.parseSum() 7.0 1.0 4.0 4.0
arithmetic.Multiple.mul(ExpressionValue, ExpressionValue) 6.0 1.0 4.0 4.0
factory.FactorFactory.getNewFactors(ArrayList) 6.0 3.0 3.0 13.0
valueobject.FactorValue.compareTo(FactorValue) 6.0 6.0 6.0 6.0
expr.factor.PowFactor.calculateValue() 5.0 1.0 4.0 4.0
valueobject.TermValue.compareTo(TermValue) 5.0 5.0 4.0 5.0
expr.factor.formula.FormulaFactor.replaceVars(String) 4.0 1.0 4.0 4.0
expr.factor.ConstantFactor.parseConst() 2.0 1.0 3.0 3.0
expr.factor.TriangleFactor.parseBase() 2.0 1.0 2.0 2.0
valueobject.ExpressionValue.compareTo(ExpressionValue) 2.0 1.0 3.0 3.0
Main.main(String[]) 1.0 1.0 2.0 2.0
expr.expression.Expression.calculateValue() 1.0 1.0 2.0 2.0
expr.expression.Expression.parseExpression() 1.0 1.0 2.0 2.0
expr.factor.PowFactor.parsePow() 1.0 1.0 2.0 2.0
expr.term.Term.calculateValue() 1.0 1.0 2.0 2.0
factory.StringFactory.replaceExtraOperation(String) 1.0 1.0 2.0 2.0
valueobject.FactorValue.canBeMerged(FactorValue) 1.0 1.0 2.0 2.0
expr.expression.Expression.Expression(String) 0.0 1.0 1.0 1.0
expr.expression.Expression.getInput() 0.0 1.0 1.0 1.0
expr.expression.Expression.getTerms() 0.0 1.0 1.0 1.0
expr.expression.Expression.getValue() 0.0 1.0 1.0 1.0
expr.expression.Expression.setInput(String) 0.0 1.0 1.0 1.0
expr.expression.Expression.setTerms(ArrayList) 0.0 1.0 1.0 1.0
expr.expression.Expression.setValue(ExpressionValue) 0.0 1.0 1.0 1.0
expr.factor.ConstantFactor.ConstantFactor(String) 0.0 1.0 1.0 1.0
expr.factor.ConstantFactor.calculateValue() 0.0 1.0 1.0 1.0
expr.factor.ConstantFactor.getNum() 0.0 1.0 1.0 1.0
expr.factor.ConstantFactor.isPositive() 0.0 1.0 1.0 1.0
expr.factor.ConstantFactor.setNum(BigInteger) 0.0 1.0 1.0 1.0
expr.factor.ConstantFactor.setPositive(boolean) 0.0 1.0 1.0 1.0
expr.factor.ExprFactor.ExprFactor(String) 0.0 1.0 1.0 1.0
expr.factor.ExprFactor.getNewExpr() 0.0 1.0 1.0 1.0
expr.factor.ExprFactor.setNewExpr(Expression) 0.0 1.0 1.0 1.0
expr.factor.Factor.Factor(String) 0.0 1.0 1.0 1.0
expr.factor.Factor.getString() 0.0 1.0 1.0 1.0
expr.factor.Factor.getValue() 0.0 1.0 1.0 1.0
expr.factor.Factor.setString(String) 0.0 1.0 1.0 1.0
expr.factor.Factor.setValue(ExpressionValue) 0.0 1.0 1.0 1.0
expr.factor.PowFactor.PowFactor(String) 0.0 1.0 1.0 1.0
expr.factor.PowFactor.getIndex() 0.0 1.0 1.0 1.0
expr.factor.PowFactor.getNewExpr() 0.0 1.0 1.0 1.0
expr.factor.PowFactor.setIndex(BigInteger) 0.0 1.0 1.0 1.0
expr.factor.PowFactor.setNewExpr(Expression) 0.0 1.0 1.0 1.0
expr.factor.TriangleFactor.TriangleFactor(String, FactorType) 0.0 1.0 1.0 1.0
expr.factor.TriangleFactor.calculateValue() 0.0 1.0 1.0 1.0
expr.factor.TriangleFactor.getBaseString() 0.0 1.0 1.0 1.0
expr.factor.TriangleFactor.getIndex() 0.0 1.0 1.0 1.0
expr.factor.TriangleFactor.getTriFactorType() 0.0 1.0 1.0 1.0
expr.factor.TriangleFactor.setBaseExpression(Expression) 0.0 1.0 1.0 1.0
expr.factor.TriangleFactor.setBaseString(String) 0.0 1.0 1.0 1.0
expr.factor.TriangleFactor.setIndex(BigInteger) 0.0 1.0 1.0 1.0
expr.factor.TriangleFactor.setTriFactorType(FactorType) 0.0 1.0 1.0 1.0
expr.factor.XFactor.XFactor(String) 0.0 1.0 1.0 1.0
expr.factor.XFactor.calculateValue() 0.0 1.0 1.0 1.0
expr.factor.formula.FormulaFactor.FormulaFactor(char, String) 0.0 1.0 1.0 1.0
expr.factor.formula.FormulaFactor.getFormulaPattern() 0.0 1.0 1.0 1.0
expr.factor.formula.FormulaFactor.getNewExpr() 0.0 1.0 1.0 1.0
expr.factor.formula.FormulaFactor.getValue() 0.0 1.0 1.0 1.0
expr.factor.formula.FormulaFactor.getVars() 0.0 1.0 1.0 1.0
expr.factor.formula.FormulaFactor.setFormulaPattern(FormulaPattern) 0.0 1.0 1.0 1.0
expr.factor.formula.FormulaFactor.setNewExpr(Expression) 0.0 1.0 1.0 1.0
expr.factor.formula.FormulaFactor.setVars(ArrayList) 0.0 1.0 1.0 1.0
expr.factor.formula.FormulaPattern.FormulaPattern(ArrayList, String) 0.0 1.0 1.0 1.0
expr.factor.formula.FormulaPattern.getFormula() 0.0 1.0 1.0 1.0
expr.factor.formula.FormulaPattern.getVarList() 0.0 1.0 1.0 1.0
expr.factor.formula.FormulaPattern.setFormula(String) 0.0 1.0 1.0 1.0
expr.factor.formula.FormulaPattern.setVarList(ArrayList) 0.0 1.0 1.0 1.0
expr.factor.formula.SumFactor.SumFactor(String) 0.0 1.0 1.0 1.0
expr.factor.formula.SumFactor.getFactor() 0.0 1.0 1.0 1.0
expr.factor.formula.SumFactor.getHigh() 0.0 1.0 1.0 1.0
expr.factor.formula.SumFactor.getLow() 0.0 1.0 1.0 1.0
expr.factor.formula.SumFactor.getNewExpr() 0.0 1.0 1.0 1.0
expr.factor.formula.SumFactor.getVars() 0.0 1.0 1.0 1.0
expr.factor.formula.SumFactor.setFactor(String) 0.0 1.0 1.0 1.0
expr.factor.formula.SumFactor.setHigh(BigInteger) 0.0 1.0 1.0 1.0
expr.factor.formula.SumFactor.setLow(BigInteger) 0.0 1.0 1.0 1.0
expr.factor.formula.SumFactor.setNewExpr(Expression) 0.0 1.0 1.0 1.0
expr.factor.formula.SumFactor.setVars(ArrayList) 0.0 1.0 1.0 1.0
expr.term.Term.Term(String) 0.0 1.0 1.0 1.0
expr.term.Term.getFactors() 0.0 1.0 1.0 1.0
expr.term.Term.getString() 0.0 1.0 1.0 1.0
expr.term.Term.getValue() 0.0 1.0 1.0 1.0
expr.term.Term.parseTerm() 0.0 1.0 1.0 1.0
expr.term.Term.setFactors(ArrayList) 0.0 1.0 1.0 1.0
expr.term.Term.setString(String) 0.0 1.0 1.0 1.0
expr.term.Term.setValue(ExpressionValue) 0.0 1.0 1.0 1.0
factory.FormulaFactory.addFormulaPattern(String) 0.0 1.0 1.0 1.0
factory.FormulaFactory.getFormulaPattern(Character) 0.0 1.0 1.0 1.0
factory.StringFactory.preprocessString(String) 0.0 1.0 1.0 1.0
factory.StringFactory.removeBlank(String) 0.0 1.0 1.0 1.0
factory.StringFactory.replacePowChar(String) 0.0 1.0 1.0 1.0
factory.StringFactory.replacePowerToStar(String) 0.0 1.0 1.0 1.0
valueobject.ExpressionValue.ExpressionValue() 0.0 1.0 1.0 1.0
valueobject.ExpressionValue.addTerm(TermValue, BigInteger) 0.0 1.0 1.0 1.0
valueobject.ExpressionValue.getExpressionValue() 0.0 1.0 1.0 1.0
valueobject.ExpressionValue.getOne() 0.0 1.0 1.0 1.0
valueobject.ExpressionValue.getZero() 0.0 1.0 1.0 1.0
valueobject.ExpressionValue.setExpressionValue(HashMap) 0.0 1.0 1.0 1.0
valueobject.FactorValue.FactorValue(FactorType, String, BigInteger) 0.0 1.0 1.0 1.0
valueobject.FactorValue.getFactorType() 0.0 1.0 1.0 1.0
valueobject.FactorValue.getIndex() 0.0 1.0 1.0 1.0
valueobject.FactorValue.getMedianExpression() 0.0 1.0 1.0 1.0
valueobject.FactorValue.setFactorType(FactorType) 0.0 1.0 1.0 1.0
valueobject.FactorValue.setIndex(BigInteger) 0.0 1.0 1.0 1.0
valueobject.FactorValue.setMedianExpression(String) 0.0 1.0 1.0 1.0
valueobject.TermValue.TermValue() 0.0 1.0 1.0 1.0
valueobject.TermValue.getTermValue() 0.0 1.0 1.0 1.0
valueobject.TermValue.setTermValue(ArrayList) 0.0 1.0 1.0 1.0
Total 213.0 166.0 219.0 251.0
Average 1.8205128205128205 1.4188034188034189 1.8717948717948718 2.1452991452991452

可以看到,第二次作业的复杂度相比第一次而言低了不少。除了在打印时对三角函数输出的特判还没有解耦之外,其余的复杂度控制得还算可以。在代码量大大增加的情况下,程序整体的复杂度还有所降低,这就说明这次作业的架构设计已经具有一定的模块化特征。

2.3 评测结果

强测全对,92.7分,互测时由于特判表达式的值为0时的输出有误,致使笔者被全房群殴6次(甚至有一个佬对我这一个错误hack两次,实在不明白这种找同质bug以后给所有找到bug的人惩罚,降低hack得分的行为。。。)

3. Homework 3

由于笔者第二次作业架构比较完整,所以第三次作业几乎没有写什么东西(肝OS实验去了,哪儿有空写这玩意儿【暴论】),仅仅针对指导书的输出范例做了一些修改,对程序的方法进行进一步解耦。然而,正是由于某些修改,笔者反而受到了正义制裁,自己写出了bug。。。

3.1 架构设计

这次作业要求支持三角函数内部的无限嵌套括号,但三角函数内部的东西必须是因子,这就意味着我得再识别一下三角函数内部的东西的输出是否为一个因子。如果是,就不用多输出一层括号;如果不是,就得加上这层括号。对于这种“毫无意义”,对表达式的化简增加烦恼的输出要求(ps. 个人拙见),我个人是感到有点恼火的,但既然课程如此要求,那我还是得继续做下去。

至于指导书里要求的其它功能,我已经在第二次作业中完成了,因此也就没再管什么。

加上第一段描述的括号功能,完成本次作业。类图如下:

(好像也没什么变化呀...没什么变化就对了hhhhh)

3.2 复杂度分析

类复杂度:

class OCavg OCmax WMC
arithmetic.Add 7.0 7.0 7.0
arithmetic.Multiple 5.5 7.0 11.0
expr.expression.Expression 1.2222222222222223 2.0 11.0
expr.factor.ConstantFactor 1.2857142857142858 3.0 9.0
expr.factor.ExprFactor 1.0 1.0 3.0
expr.factor.Factor 1.0 1.0 5.0
expr.factor.FactorType 0.0
expr.factor.formula.FormulaFactor 1.3333333333333333 4.0 12.0
expr.factor.formula.FormulaPattern 1.0 1.0 5.0
expr.factor.formula.SumFactor 1.25 4.0 15.0
expr.factor.PowFactor 1.5714285714285714 4.0 11.0
expr.factor.TriangleFactor 1.1 2.0 11.0
expr.factor.XFactor 1.0 1.0 2.0
expr.term.Term 1.1111111111111112 2.0 10.0
factory.FactorFactory 11.333333333333334 14.0 34.0
factory.FormulaFactory 3.0 7.0 9.0
factory.StringFactory 5.0 11.0 55.0
factory.TermFactory 7.0 7.0 7.0
Main 2.0 2.0 2.0
valueobject.ExpressionValue 1.2857142857142858 3.0 9.0
valueobject.FactorValue 1.5555555555555556 6.0 14.0
valueobject.TermValue 2.0 5.0 8.0
Total 250.0
Average 2.0833333333333335 4.476190476190476 11.363636363636363

方法复杂度:

method CogC ev(G) iv(G) v(G)
factory.FactorFactory.getNewFactors(ArrayList) 6.0 3.0 3.0 13.0
factory.FactorFactory.judgeFactorType(String) 12.0 11.0 11.0 12.0
factory.StringFactory.termToString(TermValue, BigInteger) 11.0 2.0 11.0 12.0
factory.StringFactory.printCosFactor(BigInteger, String, boolean) 27.0 10.0 2.0 11.0
factory.StringFactory.printSinFactor(BigInteger, String, boolean) 27.0 10.0 2.0 11.0
factory.StringFactory.exprToString(ExpressionValue) 16.0 3.0 9.0 10.0
factory.TermFactory.splitTerms(String) 14.0 1.0 7.0 10.0
factory.FactorFactory.splitFactors(String) 12.0 1.0 9.0 9.0
arithmetic.Multiple.mul(TermValue, TermValue) 14.0 1.0 8.0 8.0
arithmetic.Add.add(ExpressionValue, ExpressionValue) 13.0 4.0 7.0 7.0
factory.FormulaFactory.splitByCommon(String) 10.0 1.0 7.0 7.0
factory.StringFactory.printXFactor(BigInteger, boolean) 10.0 6.0 1.0 6.0
valueobject.FactorValue.compareTo(FactorValue) 6.0 6.0 6.0 6.0
valueobject.TermValue.compareTo(TermValue) 5.0 5.0 4.0 5.0
arithmetic.Multiple.mul(ExpressionValue, ExpressionValue) 6.0 1.0 4.0 4.0
expr.factor.PowFactor.calculateValue() 5.0 1.0 4.0 4.0
expr.factor.formula.FormulaFactor.replaceVars(String) 4.0 1.0 4.0 4.0
expr.factor.formula.SumFactor.parseSum() 7.0 1.0 4.0 4.0
factory.StringFactory.factorToString(FactorValue, boolean) 1.0 4.0 4.0 4.0
expr.factor.ConstantFactor.parseConst() 2.0 1.0 3.0 3.0
valueobject.ExpressionValue.compareTo(ExpressionValue) 2.0 1.0 3.0 3.0
Main.main(String[]) 1.0 1.0 2.0 2.0
expr.expression.Expression.calculateValue() 1.0 1.0 2.0 2.0
expr.expression.Expression.parseExpression() 1.0 1.0 2.0 2.0
expr.factor.PowFactor.parsePow() 1.0 1.0 2.0 2.0
expr.factor.TriangleFactor.parseBase() 2.0 1.0 2.0 2.0
expr.term.Term.calculateValue() 1.0 1.0 2.0 2.0
factory.StringFactory.replaceExtraOperation(String) 1.0 1.0 2.0 2.0
valueobject.FactorValue.canBeMerged(FactorValue) 1.0 1.0 2.0 2.0
expr.expression.Expression.Expression(String) 0.0 1.0 1.0 1.0
expr.expression.Expression.getInput() 0.0 1.0 1.0 1.0
expr.expression.Expression.getTerms() 0.0 1.0 1.0 1.0
expr.expression.Expression.getValue() 0.0 1.0 1.0 1.0
expr.expression.Expression.setInput(String) 0.0 1.0 1.0 1.0
expr.expression.Expression.setTerms(ArrayList) 0.0 1.0 1.0 1.0
expr.expression.Expression.setValue(ExpressionValue) 0.0 1.0 1.0 1.0
expr.factor.ConstantFactor.ConstantFactor(String) 0.0 1.0 1.0 1.0
expr.factor.ConstantFactor.calculateValue() 0.0 1.0 1.0 1.0
expr.factor.ConstantFactor.getNum() 0.0 1.0 1.0 1.0
expr.factor.ConstantFactor.isPositive() 0.0 1.0 1.0 1.0
expr.factor.ConstantFactor.setNum(BigInteger) 0.0 1.0 1.0 1.0
expr.factor.ConstantFactor.setPositive(boolean) 0.0 1.0 1.0 1.0
expr.factor.ExprFactor.ExprFactor(String) 0.0 1.0 1.0 1.0
expr.factor.ExprFactor.getNewExpr() 0.0 1.0 1.0 1.0
expr.factor.ExprFactor.setNewExpr(Expression) 0.0 1.0 1.0 1.0
expr.factor.Factor.Factor(String) 0.0 1.0 1.0 1.0
expr.factor.Factor.getString() 0.0 1.0 1.0 1.0
expr.factor.Factor.getValue() 0.0 1.0 1.0 1.0
expr.factor.Factor.setString(String) 0.0 1.0 1.0 1.0
expr.factor.Factor.setValue(ExpressionValue) 0.0 1.0 1.0 1.0
expr.factor.PowFactor.PowFactor(String) 0.0 1.0 1.0 1.0
expr.factor.PowFactor.getIndex() 0.0 1.0 1.0 1.0
expr.factor.PowFactor.getNewExpr() 0.0 1.0 1.0 1.0
expr.factor.PowFactor.setIndex(BigInteger) 0.0 1.0 1.0 1.0
expr.factor.PowFactor.setNewExpr(Expression) 0.0 1.0 1.0 1.0
expr.factor.TriangleFactor.TriangleFactor(String, FactorType) 0.0 1.0 1.0 1.0
expr.factor.TriangleFactor.calculateValue() 0.0 1.0 1.0 1.0
expr.factor.TriangleFactor.getBaseString() 0.0 1.0 1.0 1.0
expr.factor.TriangleFactor.getIndex() 0.0 1.0 1.0 1.0
expr.factor.TriangleFactor.getTriFactorType() 0.0 1.0 1.0 1.0
expr.factor.TriangleFactor.setBaseExpression(Expression) 0.0 1.0 1.0 1.0
expr.factor.TriangleFactor.setBaseString(String) 0.0 1.0 1.0 1.0
expr.factor.TriangleFactor.setIndex(BigInteger) 0.0 1.0 1.0 1.0
expr.factor.TriangleFactor.setTriFactorType(FactorType) 0.0 1.0 1.0 1.0
expr.factor.XFactor.XFactor(String) 0.0 1.0 1.0 1.0
expr.factor.XFactor.calculateValue() 0.0 1.0 1.0 1.0
expr.factor.formula.FormulaFactor.FormulaFactor(char, String) 0.0 1.0 1.0 1.0
expr.factor.formula.FormulaFactor.getFormulaPattern() 0.0 1.0 1.0 1.0
expr.factor.formula.FormulaFactor.getNewExpr() 0.0 1.0 1.0 1.0
expr.factor.formula.FormulaFactor.getValue() 0.0 1.0 1.0 1.0
expr.factor.formula.FormulaFactor.getVars() 0.0 1.0 1.0 1.0
expr.factor.formula.FormulaFactor.setFormulaPattern(FormulaPattern) 0.0 1.0 1.0 1.0
expr.factor.formula.FormulaFactor.setNewExpr(Expression) 0.0 1.0 1.0 1.0
expr.factor.formula.FormulaFactor.setVars(ArrayList) 0.0 1.0 1.0 1.0
expr.factor.formula.FormulaPattern.FormulaPattern(ArrayList, String) 0.0 1.0 1.0 1.0
expr.factor.formula.FormulaPattern.getFormula() 0.0 1.0 1.0 1.0
expr.factor.formula.FormulaPattern.getVarList() 0.0 1.0 1.0 1.0
expr.factor.formula.FormulaPattern.setFormula(String) 0.0 1.0 1.0 1.0
expr.factor.formula.FormulaPattern.setVarList(ArrayList) 0.0 1.0 1.0 1.0
expr.factor.formula.SumFactor.SumFactor(String) 0.0 1.0 1.0 1.0
expr.factor.formula.SumFactor.getFactor() 0.0 1.0 1.0 1.0
expr.factor.formula.SumFactor.getHigh() 0.0 1.0 1.0 1.0
expr.factor.formula.SumFactor.getLow() 0.0 1.0 1.0 1.0
expr.factor.formula.SumFactor.getNewExpr() 0.0 1.0 1.0 1.0
expr.factor.formula.SumFactor.getVars() 0.0 1.0 1.0 1.0
expr.factor.formula.SumFactor.setFactor(String) 0.0 1.0 1.0 1.0
expr.factor.formula.SumFactor.setHigh(BigInteger) 0.0 1.0 1.0 1.0
expr.factor.formula.SumFactor.setLow(BigInteger) 0.0 1.0 1.0 1.0
expr.factor.formula.SumFactor.setNewExpr(Expression) 0.0 1.0 1.0 1.0
expr.factor.formula.SumFactor.setVars(ArrayList) 0.0 1.0 1.0 1.0
expr.term.Term.Term(String) 0.0 1.0 1.0 1.0
expr.term.Term.getFactors() 0.0 1.0 1.0 1.0
expr.term.Term.getString() 0.0 1.0 1.0 1.0
expr.term.Term.getValue() 0.0 1.0 1.0 1.0
expr.term.Term.parseTerm() 0.0 1.0 1.0 1.0
expr.term.Term.setFactors(ArrayList) 0.0 1.0 1.0 1.0
expr.term.Term.setString(String) 0.0 1.0 1.0 1.0
expr.term.Term.setValue(ExpressionValue) 0.0 1.0 1.0 1.0
factory.FormulaFactory.addFormulaPattern(String) 0.0 1.0 1.0 1.0
factory.FormulaFactory.getFormulaPattern(Character) 0.0 1.0 1.0 1.0
factory.StringFactory.preprocessString(String) 0.0 1.0 1.0 1.0
factory.StringFactory.removeBlank(String) 0.0 1.0 1.0 1.0
factory.StringFactory.replacePowChar(String) 0.0 1.0 1.0 1.0
factory.StringFactory.replacePowerToStar(String) 0.0 1.0 1.0 1.0
valueobject.ExpressionValue.ExpressionValue() 0.0 1.0 1.0 1.0
valueobject.ExpressionValue.addTerm(TermValue, BigInteger) 0.0 1.0 1.0 1.0
valueobject.ExpressionValue.getExpressionValue() 0.0 1.0 1.0 1.0
valueobject.ExpressionValue.getOne() 0.0 1.0 1.0 1.0
valueobject.ExpressionValue.getZero() 0.0 1.0 1.0 1.0
valueobject.ExpressionValue.setExpressionValue(HashMap) 0.0 1.0 1.0 1.0
valueobject.FactorValue.FactorValue(FactorType, String, BigInteger) 0.0 1.0 1.0 1.0
valueobject.FactorValue.getFactorType() 0.0 1.0 1.0 1.0
valueobject.FactorValue.getIndex() 0.0 1.0 1.0 1.0
valueobject.FactorValue.getMedianExpression() 0.0 1.0 1.0 1.0
valueobject.FactorValue.setFactorType(FactorType) 0.0 1.0 1.0 1.0
valueobject.FactorValue.setIndex(BigInteger) 0.0 1.0 1.0 1.0
valueobject.FactorValue.setMedianExpression(String) 0.0 1.0 1.0 1.0
valueobject.TermValue.TermValue() 0.0 1.0 1.0 1.0
valueobject.TermValue.getTermValue() 0.0 1.0 1.0 1.0
valueobject.TermValue.setTermValue(ArrayList) 0.0 1.0 1.0 1.0
Total 219.0 173.0 220.0 260.0
Average 1.825 1.4416666666666667 1.8333333333333333 2.1666666666666665

可以看到,解耦对factory.StringFactory.factorToString(FactorValue, boolean)方法的复杂度的巨大改善。剩下的倒没什么区别。

3.3 评测结果

强测全对,88.6分。解耦时不小心把cos(0)的化简删了,使得本来就不富裕的强测分雪上加霜。。。互测被找到一个忘加括号的bug(要是三角函数内部没有那么多奇怪的约束我就没这个bug了!)

4. bugging & debugging

4.1 分析自己bug的策略

  1. 利用指导书上的例子对刚写完的程序进行测试。指导书将最典型的那些表达式列在了上面,利用这些可以对程序做最基础的功能性测试。
  2. 针对控制语句较复杂的程序块进行语义分析,当真值不一定为1时,程序就会存在漏洞。之后,对其进行单元测试,明确bug出现的地方。
  3. 与同学交流出现的bug,将其作为参考进行测试。
  4. 利用评测机的弱测/中测进行debug(面向评测机的编程方法)
  5. 构建随机数据生成器,用数万条表达式进行随机轰炸。

在此也分享一些我当时找到的bug:

Homework 1:

  1. 表达式因子前面的负号无法被识别;
  2. 过大的整数处理没有使用BigInteger而导致的溢出问题;
  3. +-号为3个时的情况;
  4. 奇怪位置的空格问题;
  5. 对0值的输出问题。

Homework 2

  1. 特判输出结果第一项是否为加号的时候忽略了字符串为空的情况,导致output.charAt(0)无法返回有效布尔值。
  2. 0**0=1的问题
  3. sum的下限值大于上限值时,sum的值返回0。
  4. 特判表达式结果为0的输出问题。

Homework 3

  1. 缺少括号的问题。

4.2 寻找别人bug的策略

拿到代码后,首先采用随机数据生成器对房间内所有程序进行轰炸,如果找到bug就算捡漏成功。

如果没有轰炸结果,就阅读房间内各个程序的代码,重点关注架构不清晰,内聚度高、耦合度高的代码(有一些佬将所有代码放到Main类之内,代码架构让人梦回大一《程序设计基础》《高级程序语言设计》《大学计算机基础》(各个学院都有不同的叫法,反正就那个意思吧)。。。),分析其耦合度高的代码块并对其进行重点分析。

此外,可以构建一些边界条件点进行测试。

由于对边界条件的考虑不足,我只找到了2个人的bug,自己却被同房的大佬们干烂了。。。(好在都是同质性bug)

5. 架构设计体验

开发初始,由于满脑子都是寒假Pre3的正则表达式训练,因此才有了大正则表达式解析为核心的Homework1。然而,第二次作业添加新的功能后,Homework1的架构完全报废,这种突如其来的影响确实给我带来了许多反思。

架构要优于代码开发。确定好架构以后,才能明晰下一步的开发方向。从Homework1到Homework2的重构代码,到Homework2为Homework3未雨绸缪设计功能,我感受到为架构留下充足扩展空间的重要性。面对周期为3周的迭代式开发工程,我们在完成当周的作业之余,也需要考虑未来可能要实现的一些功能,并在架构中为之作好准备。

不过,我这回从某种程度上算是开了天眼,看着括号就想到了无限嵌套括号功能的添加,于是顺手就做了出来。但在实际的工程环境下,我们的工程需要在未来添加哪些功能不会取决于于开发团队的主观臆断,而是产品端的需求。对此,我们该如何准备?或许,我们应该进一步抽象化,留出开发接口以供未来使用,而非是直接在工程上大改特改。

6. 心得体会

这是我第一次体验北航OO的“历史周期律”。

这是我上第一节OO课时了解到课设安排后,脑袋里第一个闪过的词。为什么叫“历史周期律”呢?因为这课没有期末考试,成绩就靠4个单元的训练:每个Unit有4周时间,3周写Project,1周写Blog。4周实验会有16学时的课与实验,其中8个学时上课,4个学时的实验与4个学时的研讨课交替进行,坚持4个单元的学习周期,这门课也就结束了。

起初我非常不适应这样的节奏安排,认为平常工作日的时间几乎都得用来学习这门课程:我平日白天上课得惦记着指导书上写了些什么,晚上要写OO课设代码,一周一半时间得用来思考怎么设计架构,小一半狂赶代码,甚至我在周末回家吃晚饭的时候,还得捧着饭碗、守在电脑前给测试房里的匿名同学找bug。对于我来说,吴际老师负责的这门OO课在某些层面上比高小鹏老师的CO要更折磨人。可以说,这门课全方面无死角的占据了我平淡的生活。

不过,这就是这门课的推背感吧。这门课程带给我的工程训练量对于从前的我来说是不敢想象的。我以前在士嘉书院读书,作为航类书院,《程序设计基础》这门课放在大一下开课,但由于我二选转到高工,而高工在大一上与信息类一样开完了程设课,因此我只能在新大二的暑假补修程设(这门课甚至是在我选专业到6系之后才上的)。从过去一行代码都不会写的小白,到现在被逼急的时候一天coding 1000+行代码的菜鸡,虽说跟大佬们比起来我的水平差得很远,但6系这些课为我带来的成长是清晰可见的。因此,我很感激6系对我的教育。

回想起第一周第二周周四周五的晚上,当时我在架构设计方面感觉灵光乍现,突然想通自己困惑的许多架构设计问题时,那种由内而外散发出的喜悦让我想到了阿基米德的Eureka时刻。在那时,我是真心享受这门课程带给我的成就感。

希望这种喜悦能够继续下去。

祝大家所有程序没有bug,祝所有的测试都AC,祝大家与WA永不相见,祝之后的课程顺利完成。

标签:OO,1.0,String,0.0,Parser,expr,factor,Unit1,2.0
来源: https://www.cnblogs.com/Monument-Valley/p/16052897.html