OO Unit1 总结

唐逸凡-24231209 2026-03-28 17:00:04

OO Unit1 总结

img

一、 类设计总体情况

表达式解析类

类/接口方法数量代码长度说明
Factor00因子接口,表达式的任何组成部分都可视为因子
Expr635行项组
Term746行因子组
Power426行一个因子及其指数
Deriver530行求导因子
Number637行常数因子
Var437行变量因子
Exp15173行指数函数因子
Selector457行选择式,未使用Factor接口,在处理阶段就完成计算与替换
Func767行函数,未使用Factor接口,在处理阶段就完成替换
RecurseFunc564行Func子类,处理同上

多项式计算类

类/接口方法数量类长度说明
Poly13250行多项式类,使用HashMap实现,同时包含+,-,*,^以及求导等多种运算
Key556行自定义的Poly类的HashMap的键,包含exponentX,exponentYExp三个属性
Visitor727行访问者模式接口
Displayer7151行具体访问者类

处理类

类/接口方法数量类长度说明
Lexer8109行解析
Parser589行递归下降
Dealer17385行处理类,包括了输入处理和输出打印,选择式和函数的替换都在这里完成

复杂度分析

MethodCogCev(G)iv(G)v(G)
Main.main(String[])0111
expression.Deriver.Deriver(Expr, String)0111
expression.Deriver.accept(Visitor)0111
expression.Deriver.getExpr()0111
expression.Deriver.getType()0111
expression.Deriver.toPoly(Visitor)0111
expression.Exp.Exp(String)0111
expression.Exp.accept(Visitor)0111
expression.Exp.deX()0111
expression.Exp.deY()0111
expression.Exp.equals(Object)5435
expression.Exp.getExp()0111
expression.Exp.getHashMap(HashMap<Key, BigInteger>)4133
expression.Exp.getPoly()0111
expression.Exp.getPolySize()0111
expression.Exp.mul(Exp)0111
expression.Exp.optimize()9177
expression.Exp.parse()2122
expression.Exp.pow(int)0111
expression.Exp.toPoly()0111
expression.Exp.toString()8356
expression.Expr.Expr()0111
expression.Expr.accept(Visitor)0111
expression.Expr.addOp(String)0111
expression.Expr.addTerm(Term)0111
expression.Expr.getOps()0111
expression.Expr.getTerms()0111
expression.Func.Func(String)0111
expression.Func.body()0111
expression.Func.getBody(String)5144
expression.Func.getFunc()0111
expression.Func.getParam()0111
expression.Func.parse()4444
expression.Func.setParam(String)0111
expression.Key.Key(BigInteger, BigInteger, Exp)0111
expression.Key.equals(Object)126610
expression.Key.getExp()0111
expression.Key.getExponentX()0111
expression.Key.getExponentY()0111
expression.Number.Number(BigInteger)0111
expression.Number.accept(Visitor)0111
expression.Number.getNum()0111
expression.Number.getNumber()0111
expression.Number.toPoly()0111
expression.Number.toString()0111
expression.Poly.Poly(HashMap<Key, BigInteger>)0111
expression.Poly.add(Poly)9245
expression.Poly.copyPoly()0111
expression.Poly.deX()7144
expression.Poly.deY()7144
expression.Poly.derivative(String)1444
expression.Poly.getExists(HashMap<Key, BigInteger>, Key)3323
expression.Poly.getMap()0111
expression.Poly.mul(Poly)8255
expression.Poly.power(BigInteger)8344
expression.Poly.sub(Poly)9245
expression.Poly.toMap()0111
expression.Poly.toString()0111
expression.Power.Power(Factor, Factor)0111
expression.Power.accept(Visitor)0111
expression.Power.getBase()0111
expression.Power.getExponent()0111
expression.RecurseFunc.RecurseFunc(String, Func, Func)0111
expression.RecurseFunc.expand(int)3333
expression.RecurseFunc.getBody(String)5144
expression.RecurseFunc.setCurse(int)0111
expression.RecurseFunc.setFunc(Func)0111
expression.Selector.Selector(String, Func, RecurseFunc)0111
expression.Selector.getRes()2212
expression.Selector.parseSelect()0111
expression.Selector.select()0111
expression.Term.Term()0111
expression.Term.accept(Visitor)0111
expression.Term.addFactors(Factor)0111
expression.Term.addOps(String)0111
expression.Term.getFactors()0111
expression.Term.getOps()0111
expression.Term.toString()1122
expression.Var.Var(String)0111
expression.Var.accept(Visitor)0111
expression.Var.toPoly()2123
expression.Var.toString()0111
parse.Lexer.Lexer(String)0111
parse.Lexer.getDerive()2133
parse.Lexer.getExp()7555
parse.Lexer.getNum(String)2133
parse.Lexer.next()7257
parse.Lexer.peek()0111
parse.Lexer.removeFront0(String)4223
parse.Lexer.toString()0111
parse.Parser.Parser(Lexer)0111
parse.Parser.parseExpr()2133
parse.Parser.parseFactor()7577
parse.Parser.parsePower()2222
parse.Parser.parseTerm()1122
visitor.Dealer.Dealer()0111
visitor.Dealer.addBracket()5134
visitor.Dealer.addZero()112610
visitor.Dealer.changeSub()6155
visitor.Dealer.deal()2133
visitor.Dealer.eleString(Key, BigInteger)5146
visitor.Dealer.getArg()6245
visitor.Dealer.getSelect(int)3323
visitor.Dealer.getValueStr(BigInteger, BigInteger, String)3411010
visitor.Dealer.getVarStr(BigInteger, String, String)3323
visitor.Dealer.print(Poly)9758
visitor.Dealer.readInput()5134
visitor.Dealer.removeAdd()8135
visitor.Dealer.removeNull(Poly)4234
visitor.Dealer.replaceFunc()212910
visitor.Dealer.replaceSelect()0111
visitor.Dealer.setDealer(String, Func, RecurseFunc)0111
visitor.Displayer.visit(Deriver)0111
visitor.Displayer.visit(Exp)0111
visitor.Displayer.visit(Expr)10356
visitor.Displayer.visit(Number)0111
visitor.Displayer.visit(Power)9899
visitor.Displayer.visit(Term)12899
visitor.Displayer.visit(Var)0111
ClassOCavgOCmaxWMC
Main111
expression.Deriver115
expression.Exp1.87528
expression.Expr116
expression.Func1.86413
expression.Key2610
expression.Number116
expression.Poly3.08540
expression.Power114
expression.RecurseFunc2410
expression.Selector1.2525
expression.Term1.1428
expression.Var1.536
parse.Lexer2.75622
parse.Parser2.4512
visitor.Dealer4.241072
visitor.Displayer4928
Packagev(G)avgv(G)tot
11
expression1.84149
parse339
visitor4.62111
Modulev(G)avgv(G)tot
oo_homework_2026_24231209_hw32.52300
Projectv(G)avgv(G)tot
project2.52300

架构反思

  1. 层次设计问题:整体看来,代码的层次还是比较清晰的,基本就是按照预处理->解析->组装计算的流程进行。但是在某些类的局部设计可以看出来打破了这个层次。
    比如对于Exp类,内部一个属性为inPoly,就是exp内部的表达式,那么为了得到这个表达式,就需要在内部进行一遍这样的流程,所以在局部其实就已经有点打乱了层次的设计。包括在Dealer中直接替换选择表达式,也是类似的操作。这样虽然可以简化后续的很多计算,但是这样会导致很深的递归,所以在处理

     1
     f(x)=exp(exp(exp(exp(exp(exp(exp(exp(x))))))))+x
     0
     f(f(f(f(x))))
    

    这样的嵌套的时候时间就爆了

  2. 预处理:可以说我Dealer中的预处理方式简直烂爆了。我一开始想的是写一个能够处理各种人能理解的输入,不单单只能处理指导书给出的合法输入。所以,我用了4个方法来处理表达式,结果只能处理无限连续加减号的额外情况,反而还引入了不少错误。

  3. 复杂度分析:总体看来复杂度似乎问题不是很大,中间某些方法和类由于分支特判比较多,可能圈复杂度v(G)比较高,部分方法复用情况比较多,基本复杂度和耦合复杂度比较高


总体来说,存在的大部分问题是小问题,可以在局部可以解决。但是复合层数过高导致的时间爆炸对我的设计来说是致命的,不管能修多少小bug,这里有问题只能重写了。唉,还是贪图方便把自己的架构搞得不伦不类的。

二、迭代体验

hw1初步设计

第一次作业,主要难点在于怎么设计主要层次。我第一次作业的层次架构感觉还是可以的,处理->解析->组装计算的设计还是很清晰的。


这一部分主要完成了Factor,Expr,Power,Lexer,Parser,Dealer,Visitor,Displayer,Poly的设计,基本架构实现。

  • 还未引入指数函数,采用TreeMap实现Poly,方便最后根据指数高低进行打印。

hw2第二次迭代

第二次迭代,新增指数函数,自定义函数以及选择表达式。


新增Exp,Selector,FuncKey类。

  • 此处由于加入指数函数,所以多项式类的键需要作出修改,不能再只有指数,还有包含exp,所以定义了Key类,作为Poly的新的键。但是由于自定义类要实现排序需要重写equal()hashCode()方法,捣鼓半天都不对,所以放弃排序了,换成HashMap来实现了。
  • SelectorFunc类不论以何种形式,都需要从表达式中被替换掉。我想到的最好的办法就是直接在一开始处理的时候直接替换掉。对于函数,只是单纯的字符串替换;但是对于选择式,还需要进行计算,这就要求同样走一遍完整的过程得到结果。当然了,这是可以实现的,而且还挺方便。
  • Exp我将其视为一个因子,内部有一个string的属性,接收内部的字符串形式表达式,然后在类内进行表达式展开于计算,从而可以得到一个inPoly的内部多项式,后续关于exp的计算也都可以直接利用Poly内已经写好的计算方法实现。

从这里开始,我的层次化设计开始出现问题了,在内部层次反复调用最顶层的操作,同时基本都是递归调用,不方便调试。

hw3 迭代作业

第三次迭代,新增y变量和递推函数


新增Deriver,RecurseFunc类,分别用于处理求导因子和计算递推函数

  • 在parser中新增对求导因子的判断,内部属性为一个Expr。同时在Poly中新增三个方法derivate,deX,deY
  • RecurseFuncFunc的子类,具体的替换方式也一样,都是在Dealer中进行替换。不过由于递推函数需要递归才能得到正常表达式,所以该类内部通过一个方法递归调用Dealer实现对函数的递归解析。
  • 由于新增y变量,所以Var在返回的时候需要进行特判。同时Key中的指数也需要加上y的指数,所以修改为exponentXexponentY

总体来说,如果前面的架构好的话,第三次迭代其实不算难。我在第二次作业的基础上,只花了1个小时左右的时间就完成了。

三、我的bug

  • 第一次迭代
    第一次迭代主要是Dealer对表达式的预处理出了一些问题

  • 第二次迭代
    主要存在三个bug:

    1. 依然是Dealer对表达式的处理出了问题
    2. 没想到第二次作业的指数允许爆int,所以把指数从int改到BigInteger就修好了
    3. 选择式的结果部分有多层嵌套的函数调用时,解析会导致超出时间限制。这里的解决方法就是Dealer中函数替换和选择式计算换一个顺序就行。
  • 第三次迭代
    主要存在两个bug

    1. 加入求导方法后,如果结果为0,那么我是直接返回一个空Poly,但是这就会导致空指针错误
    2. 这个bug是我整个代码最致命的bug,就是在嵌套过深的情况下,运行时间会爆。这当然是因为我破坏层次的两个处理:直接字符串替换函数以及在exp内部进行表达式计算。后者是主要原因,一个30层左右的exp嵌套,意味着exp内部的表达式替换需要递归30层,每一层又需要遍历传入的字符串,解析,组装,所以运行时间爆了是必然结果。

第二个bug,在现在代码的基础上基本没法修。要修的话必须把修改ExpinPoly属性,但是我后续与exp相关的所有计算和多项式的构建都基于此,这个东西一删,和重写基本没有区别。

目前的重构打算是把Dealer里进行函数替换和选择式替换的部分全部删掉,将函数与选择式视为因子,在parser里一起解析。exp也不进行内部解析了,把本来输入为String的构造函数改为输入Expr,最后都统一在Display中进行组装计算

四、找别人bug的策略

  1. 利用评测机生成数据
  2. 让AI帮忙查找别人的bug
  3. 自己从头到尾看别人的代码

五、 我的优化

我在输出的优化上并没有思考很多。
第一次作业,基本没有优化,其实也不需要,最短的输出就是确保第一个项的系数是正的
第二次作业,我完全没有考虑优化,exp的指数直接全部乘进去了
第三次作业,我只做了一点优化,就是对于把系数相同的提取系数,然后提出来作为指数,与常规的输出进行长度判断后输出。

六、 大模型使用

  1. 在我的作业过程中,大模型只起到辅助作用。每一次作业,代码架构基本都是由我自己构思的,但是在一些具体的实现上,我可能会向AI寻求一些建议。比如,使用访问者模式进行最后的组装计算就是AI给的建议。包括碰到的一些问题,比如重写hashmap的equals方法,这些自己没法解决,就向AI寻求帮助。
    我可以说自己代码的AI率不会超过5%。其实我也用AI生成了很多代码,但是不用AI的代码主要是因为感觉自己脑回路和AI对不上,它给10条建议,采用1条已经算是很有用了。

  2. 评测的时候使用AI就比较多了。除了第一次作业的评测机是自己写的外,后面两次都是用的AI生成的评测机,还是很好用的。

  3. 同房的同学代码看得很少,就算看了,其实我也不太能分辨出来是不是AI写的。我对AI的直觉还是挺差的

七、 心得体会

我感觉最大的体会还是在于AI的使用吧。
其实这3次作业的成绩还是挺差的,每一次都在c房,但是我又能看到好多同学几乎完全依靠AI,可以进b甚至a房。而且我做作业的效率很低,第一次作业写了几乎3个下午夹晚上,但是有的同学半天就写完了。从这样的对比中可以看出,利用好AI,对写代码真的是有很大的提升。

另外一个就是不要贪图方便而放弃规范性。如果当时没有为了贪图最后计算的简便,而是老老实实把函数,选择式和exp写成规范的因子,也不会出现这样致命的bug了。能不能在debug截至之前重写完就听天由命了。

...全文
72 回复 打赏 收藏 转发到动态 举报
写回复
用AI写文章
回复
切换为时间正序
请发表友善的回复…
发表回复

309

社区成员

发帖
与我相关
我的任务
社区描述
2026年北航面向对象设计与构造
java 高校
社区管理员
  • 孙琦航
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧