BUAA OO 第一单元总结

BUAA OO 第一单元总结


第一次作业

1.基本思路

总体来说,我采用了第一单元训练中的思想,即对表达式各部分进行建模,然后用递归下降法解析整个表达式

2.具体设计

|- administration (package) : 控制单元
    |- MainClass : 主类
    |- Parser : 解析表达式
    |- Simplifier : 化简表达式
|- expression (package) : 表达式建模
    |- Expression : 表达式
    |- Factor : 因子
    |- NumberFactor : 常数
    |- PowerFunction : 幂函数
    |- Term : 项

avatar

avatar

Parser类用来解析表达式并构建因子和项。其中Expression用一个ArrayList来存储Terms,Term则用一个ArrayList来存储Factors

Simplifier类用来化简表达式。化简时会把主表达式里所有的Term都转化为"简单Term",简单Term只包含系数及幂次,方便合并同类项和输出

为了缩短表达式,我采用了以下几种方法:

  • 合并同类项
  • 将x*2输出为xx
  • 如果有正系数项,将正系数项提前输出,即不输出"-x+1",输出"1-x"

3.复杂度分析

类复杂度:

Class OCavg OCmax WMC
administration.MainClass 1.00 1 2
administration.Parser 3.25 12 26
administration.Simplifier 4.50 15 27
expression.Expression 1.75 10 21
expression.NumberFactor 1.00 1 7
expression.PowerFunction 1.33 3 8
expression.Term 1.17 3 14

方法复杂度:

Method CogC ev(G) iv(G) v(G)
administration.MainClass.input() 0 1 1 1
administration.MainClass.main(String[]) 0 1 1 1
administration.Parser.Parser(String) 0 1 1 1
administration.Parser.cur() 1 2 1 2
administration.Parser.getFullExpr() 0 1 1 1
administration.Parser.next() 1 2 1 2
administration.Parser.parseExponent(Factor) 3 1 4 4
administration.Parser.parseExpression(boolean) 2 1 3 3
administration.Parser.parseNumber() 3 1 4 4
administration.Parser.parseTerm() 30 7 16 16
administration.Simplifier.Simplifier(Expression) 0 1 1 1
administration.Simplifier.expandTerm(Term) 27 1 14 17
administration.Simplifier.getFullExpr() 0 1 1 1
administration.Simplifier.multTerms(Term,Term) 0 1 1 1
administration.Simplifier.multiply(ArrayList<Term>,Expression) 3 1 3 3
administration.Simplifier.simExpression(Expression) 9 4 6 6
expression.Expression.Expression() 0 1 1 1
expression.Expression.Expression(boolean) 0 1 1 1
expression.Expression.addTerm(Term) 0 1 1 1
expression.Expression.getExponent() 0 1 1 1
expression.Expression.getTerms() 0 1 1 1
expression.Expression.info() 0 1 1 1
expression.Expression.isPositive() 0 1 1 1
expression.Expression.popTerm() 0 1 1 1
expression.Expression.setExponent(int) 0 1 1 1
expression.Expression.setPositive(boolean) 0 1 1 1
expression.Expression.setTerms(ArrayList<Term>) 0 1 1 1
expression.Expression.toString() 15 7 7 10
expression.NumberFactor.NumberFactor(BigInteger) 0 1 1 1
expression.NumberFactor.getExponent() 0 1 1 1
expression.NumberFactor.getValue() 0 1 1 1
expression.NumberFactor.info() 0 1 1 1
expression.NumberFactor.setExponent(int) 0 1 1 1
expression.NumberFactor.setValue(BigInteger) 0 1 1 1
expression.NumberFactor.toString() 0 1 1 1
expression.PowerFunction.PowerFunction() 0 1 1 1
expression.PowerFunction.PowerFunction(int) 0 1 1 1
expression.PowerFunction.getExponent() 0 1 1 1
expression.PowerFunction.info() 0 1 1 1
expression.PowerFunction.setExponent(int) 0 1 1 1
expression.PowerFunction.toString() 3 3 1 3
expression.Term.Term() 0 1 1 1
expression.Term.Term(BigInteger,int) 0 1 1 1
expression.Term.addFactor(Factor) 0 1 1 1
expression.Term.coefficientSign() 0 1 1 1
expression.Term.getCoefficient() 0 1 1 1
expression.Term.getExponent() 0 1 1 1
expression.Term.getFactor() 0 1 1 1
expression.Term.getFactors() 0 1 1 1
expression.Term.info() 0 1 1 1
expression.Term.setCoefficient(BigInteger) 0 1 1 1
expression.Term.setExponent(int) 0 1 1 1
expression.Term.toString() 4 3 4 4

从复杂度分析可以看出,我的类复杂度把控得不均匀,最主要的功能都集中到了administrator中的几个类里

值得一提的是,我的Simplifier类里还包含了好几个private方法,供本类调用。现在想来,这不就是经典的面向过程思想吗

4.Bug分析

由于时间安排不恰当,这次作业我并没有做自动化测试工具。手造了一些测试样例,过了中测之后就没再管自己的代码了

最后互测时被找出了-(1)**0化简为1的bug。直接原因是我直接把Term中指数为0的Factor剔除了,根本原因是特殊化处理时没有考虑周全,以及没有做强力的测试

由于被分配到了A房,而且没有自动测试工具,我没能找出别人的bug


第二次作业

1.迭代思路

在增量开发之前,我对自己的代码进行了一定规模的重构

  • 我新建了Inputer类来完成输入工作
  • 我还去掉了Simplify类,将化简方法封装到了ComplicatedTerm类里,大大加强了面向对象的风格。不过还是没能消灭掉multExpressions和multTerms这两个private方法
  • 我改进了Parser类中的parseTerm方法,使其复杂度降低,Parser类也因此变得逻辑清晰

第二次作业中添加了一些新元素,我的处理方案如下:

  • 对于新增的自定义函数,我在预处理表达式时就把它们替换掉了

  • 对于新增的求和函数,我新建了Sum类来对它建模,化简时将Sum函数展开成表达式即可

  • 对于新增的三角函数,我新建了Tri类,并用Sin类和Cos类继承Tri类,对其建模

2.具体设计

|- administration (package) : 控制单元
    |- MainClass : 主类
    |- Parser : 解析表达式
    |- Input : 读取表达式
|- expression (package) : 表达式建模
    |- Expression : 表达式
    |- Factor : 因子
    |- NumberFactor : 常数
    |- PowerFunction : 幂函数
    |- SimpleTerm : 简单项
    |- ComplicatedTerm : 复杂项
    |- Sum : 求和函数
    |- Tri : 三角函数
    |- Sin : Sin函数
    |- Cos : Cos函数
    |- LoopVariable : 求和函数
    |- BaseFactor : 三角函数的底数因子
|- index (package) : HashMap索引
    |- SimpleTermIndex : SimpleTerm的索引
    |- TriIndex : 三角函数的索引

avatar

avatar

avatar

这次,我将Term分离为化简前的ComplicatedTerm和化简后的SimpleTerm。

为了合并同类项,我在SimpleTerm里用HashMap来存储三角函数,在Expression里用HashMap来存储SimpleTerms,并且实现了相关类的equals和hashCode方法,还专门建立了索引类来充当HashMap的Key

不过,我没有做平方和与二倍角优化

3.复杂度分析

类复杂度:

Class OCavg OCmax WMC
administration.Inputer 3.50 9 14
administration.MainClass 1.00 1 1
administration.Parser 2.86 12 40
expression.ComplicatedTerm 3.89 16 35
expression.Cos 1.50 3 6
expression.Expression 2.20 9 22
expression.LoopVariable 1.00 1 3
expression.NumberFactor 1.25 3 10
expression.PowerFunction 1.71 4 12
expression.SimpleTerm 2.00 9 20
expression.Sin 1.50 3 6
expression.Sum 1.25 2 5
expression.Tri 1.18 3 13
index.SimpleTermIndex 1.40 3 7
index.TriIndex 1.40 3 7

方法复杂度:

Method CogC ev(G) iv(G) v(G)
administration.Inputer.Inputer() 0 1 1 1
administration.Inputer.expandFunction(String) 12 3 6 9
administration.Inputer.getInputString() 0 1 1 1
administration.Inputer.input() 2 1 3 3
administration.MainClass.main(String[]) 0 1 1 1
administration.Parser.Parser(String) 0 1 1 1
administration.Parser.cur() 1 2 1 2
administration.Parser.getFullExpr() 0 1 1 1
administration.Parser.parseBound() 1 1 2 2
administration.Parser.parseCos() 6 5 4 5
administration.Parser.parseExponent(Factor) 1 1 2 2
administration.Parser.parseExpression() 2 1 3 3
administration.Parser.parseFactor(ComplicatedTerm) 12 10 11 12
administration.Parser.parseLoopVariable() 0 1 1 1
administration.Parser.parseNumberFactor() 1 1 2 2
administration.Parser.parsePowerFunction() 0 1 1 1
administration.Parser.parseSin() 6 5 4 5
administration.Parser.parseSum() 0 1 1 1
administration.Parser.parseTerm() 4 1 3 4
expression.ComplicatedTerm.ComplicatedTerm() 0 1 1 1
expression.ComplicatedTerm.addFactor(Factor) 0 1 1 1
expression.ComplicatedTerm.expand() 27 5 16 18
expression.ComplicatedTerm.getFactors() 0 1 1 1
expression.ComplicatedTerm.lastFactor() 0 1 1 1
expression.ComplicatedTerm.multExpressions(ArrayList<SimpleTerm>,ArrayList<SimpleTerm>) 3 1 3 3
expression.ComplicatedTerm.multTerms(SimpleTerm,SimpleTerm) 2 1 3 3
expression.ComplicatedTerm.replaceI(BigInteger) 15 1 8 8
expression.ComplicatedTerm.toString() 0 1 1 1
expression.Cos.Cos(BaseFactor) 0 1 1 1
expression.Cos.Cos(BaseFactor,int) 0 1 1 1
expression.Cos.Cos(TriIndex,int) 0 1 1 1
expression.Cos.toString() 2 3 2 3
expression.Expression.Expression() 0 1 1 1
expression.Expression.addComplicatedTerm(ComplicatedTerm) 0 1 1 1
expression.Expression.addSimpleTerm(SimpleTerm) 2 1 2 2
expression.Expression.getComplicatedTerms() 0 1 1 1
expression.Expression.getExponent() 0 1 1 1
expression.Expression.getSimpleTerms() 0 1 1 1
expression.Expression.replaceI(BigInteger) 1 1 2 2
expression.Expression.setExponent(int) 0 1 1 1
expression.Expression.simplify() 3 1 3 3
expression.Expression.toString() 12 4 7 9
expression.LoopVariable.LoopVariable() 0 1 1 1
expression.LoopVariable.getExponent() 0 1 1 1
expression.LoopVariable.setExponent(int) 0 1 1 1
expression.NumberFactor.NumberFactor(BigInteger) 0 1 1 1
expression.NumberFactor.equals(Object) 4 3 3 5
expression.NumberFactor.getExponent() 0 1 1 1
expression.NumberFactor.getValue() 0 1 1 1
expression.NumberFactor.hashCode() 0 1 1 1
expression.NumberFactor.setExponent(int) 0 1 1 1
expression.NumberFactor.setValue(BigInteger) 0 1 1 1
expression.NumberFactor.toString() 0 1 1 1
expression.PowerFunction.PowerFunction() 0 1 1 1
expression.PowerFunction.PowerFunction(int) 0 1 1 1
expression.PowerFunction.equals(Object) 3 3 2 4
expression.PowerFunction.getExponent() 0 1 1 1
expression.PowerFunction.hashCode() 0 1 1 1
expression.PowerFunction.setExponent(int) 0 1 1 1
expression.PowerFunction.toString() 4 4 1 4
expression.SimpleTerm.SimpleTerm() 0 1 1 1
expression.SimpleTerm.SimpleTerm(BigInteger,int) 0 1 1 1
expression.SimpleTerm.SimpleTerm(SimpleTermIndex,BigInteger) 0 1 1 1
expression.SimpleTerm.addTri(Tri) 5 1 3 3
expression.SimpleTerm.coefficientSign() 0 1 1 1
expression.SimpleTerm.getCoefficient() 0 1 1 1
expression.SimpleTerm.getExponent() 0 1 1 1
expression.SimpleTerm.getTris() 0 1 1 1
expression.SimpleTerm.setCoefficient(BigInteger) 0 1 1 1
expression.SimpleTerm.toString() 14 2 11 11
expression.Sin.Sin(BaseFactor) 0 1 1 1
expression.Sin.Sin(BaseFactor,int) 0 1 1 1
expression.Sin.Sin(TriIndex,int) 0 1 1 1
expression.Sin.toString() 2 3 2 3
expression.Sum.Sum(BigInteger,BigInteger,ComplicatedTerm) 0 1 1 1
expression.Sum.expand() 1 1 2 2
expression.Sum.getExponent() 0 1 1 1
expression.Sum.setExponent(int) 0 1 1 1
expression.Tri.Tri(BaseFactor) 0 1 1 1
expression.Tri.Tri(BaseFactor,int) 0 1 1 1
expression.Tri.Tri(TriIndex,int) 0 1 1 1
expression.Tri.absValue() 0 1 1 1
expression.Tri.coefficientSign() 0 1 1 1
expression.Tri.equals(Object) 4 3 3 5
expression.Tri.getBaseFactor() 0 1 1 1
expression.Tri.getExponent() 0 1 1 1
expression.Tri.hashCode() 0 1 1 1
expression.Tri.setExponent(int) 0 1 1 1
expression.Tri.toString() 0 1 1 1
index.SimpleTermIndex.SimpleTermIndex(SimpleTerm) 0 1 1 1
index.SimpleTermIndex.equals(Object) 4 3 3 5
index.SimpleTermIndex.getExponent() 0 1 1 1
index.SimpleTermIndex.getTris() 0 1 1 1
index.SimpleTermIndex.hashCode() 0 1 1 1
index.TriIndex.TriIndex(Tri) 0 1 1 1
index.TriIndex.equals(Object) 4 3 3 5
index.TriIndex.getBaseFactor() 0 1 1 1
index.TriIndex.hashCode() 0 1 1 1
index.TriIndex.isSin() 0 1 1 1

这次的复杂度就比上次均匀一些,但仍有很多值得改进的地方:

  • Sin类和Cos类空洞无比,还不如直接在Tri类里用一个boolean变量来区分sin和cos
  • 大可不必使用BaseFactor类来作为三角函数中的因子,直接用Factor会更好
  • SimpleTerm和ComplicatedTerm的区分大大增加了思维的复杂度。既然使用了HashMap,还不如在化简时直接使用ComplicatedTerm的形式

最后一点是本次作业乃至本单元最大的决策失误,不知道因此浪费了多少时间

这也提醒了我,以后在进行面向对象开发时,一定要保持架构的简洁性,万万不可因为一个小地方的"特殊化"就把整个架构给毁了

4.Bug分析

我本单元第二大的决策失误就出在这里,我的代码少提交了一个版本,导致sin和cos函数里出现正负号都无法分析。于是我强测多错了3个点,互测也被hack烂了

我强测错的另一个点是程序结果中出现了sin(x*x)这样不合法的表达式

还有一个Bug是sin(-1)**2结果为-sin(1)**2,是自己在提出三角函数中负号的时候没有考虑周全

总之,这次出了3个bug,和自己复杂的架构脱不了干系

不过,由于做了自动化测试程序,我也找出了其他人的bug


第三次作业

1.迭代过程

如果第二次作业的程序拓展性强,这次作业基本上是不需要增量开发的

可惜我的程序不满足这一点。我在预解析表达式时将自定义函数替换的策略不再适用,这次我不得不重新对自定义函数进行建模

而且,我又一次对自己的代码进行了重构

倒是干了一些人事,比如把Sin和Cos类删掉了,还把Factor从接口改成了抽象类,实现了一些代码的复用

但是:不仅没有合并ComplicatedTerm和SimpleTerm,还把Expression也分成了ComplicatedExpression和SimpleExpression

可笑的是:也没有任何优化

更可笑的是:就这还花费了两天的时间

现在的情况是:我已经不想再多看自己的代码一眼了,因为已经被我重构成垃圾堆了

现在应该做的是:在下一单元的开发中避免这次的情况

2.Bug分析

由于有自动化测试程序,并且没有忘记提交最新版本,我强测没有出现Bug

但是,互测时,我被hack出了一个bug:我的程序从头到尾都没有管常数的幂次,所以sum(i,2,2,i**2)的化简结果为2

我hack出的别人的bug也都是和sum函数有关的,比如下限大于上限则报错,上下限不能超过int范围


总结

大概从二月二十几号开始,我的生活和OO的耦合度一直居高不下

还没开学,就已经有了计组实验的压迫感。闲暇时间急剧下降,已经好久没有发展过自己的兴趣爱好了

不过,终于熬到了今天。在下一单元开始之前,至少可以度过一个正常的周末

一定范围内,工作量和收益正相关。蓦然回首,发现自己已经在面向对象的路上走了一段还算远的距离

Pre2中,我学到了面向对象的基本思想和Java的一些基础语法,了解了Comparable接口并用sort函数将对象排序

Pre3中,我学会了利用正则表达式处理字符串的几种方法,还第一次画了UML类图

第一次作业,我学到了递归下降法,知道了表达式该如何解析

第二次作业,我了解并实践了equals与hashCode方法的重写,并将其用于HashMap中Key的比较

第三次作业,我了解了Cloneable接口,实现了对象的深克隆。我还了解了不可变对象,对象之间的关系在脑海中变得越来越清晰

甚至在写博客的时候,我还学到了"图片转base64码导入md文件"、"csv格式文件转Markdown表格"等实用技巧

我相信以上提到的知识对于以后的工作都是很有帮助的。这一个月虽然辛苦,但不可否认收获颇丰

期待下一单元

posted @ 2022-03-26 00:58  马又SYQ  阅读(20)  评论(0编辑  收藏  举报