2026 BUAA-OO-Unit1总结

杨启桐24373180 2026-03-27 21:40:15

一、项目结构度量分析

代码度量分析

ClassOCavgOCmaxWMC
ChoiceFactor1.5023
DeriveFactor1.5023
ExpFactor1.5023
Expr1.5023
ExprFactor1.0012
Factor1.0013
FuncCallFactor1.0012
FuncDef1.0013
Lexer4.002240
MainClass3.0059
Mono1.82520
NumFactor1.0012
Parser5.181557
Poly4.251085
RecursiveFuncCallFactor1.0012
RecursiveFuncDef4.0078
RecursiveFuncDefParser3.33820
Term1.3324
Token1.0013
Token.Typen/an/a0
VarFactor1.5023
MethodCogCev(G)iv(G)v(G)
ChoiceFactor.ChoiceFactor(Factor, Factor, Factor, Factor)0111
ChoiceFactor.toPoly()2222
DeriveFactor.DeriveFactor(Expr, String)0111
DeriveFactor.toPoly()2122
ExpFactor.ExpFactor(Factor)0111
ExpFactor.toPoly()1222
Expr.addTerm(Term)0111
Expr.toPoly()1122
ExprFactor.ExprFactor(Expr)0111
ExprFactor.toPoly()0111
Factor.getIndex()0111
Factor.setIndex(int)0111
Factor.toPoly()0111
FuncCallFactor.FuncCallFactor(FuncDef, Factor)0111
FuncCallFactor.toPoly()0111
FuncDef.FuncDef(String, Expr)0111
FuncDef.getBody()0111
FuncDef.getParamName()0111
Lexer.Lexer(String)0111
Lexer.getCurrentToken()0111
Lexer.getIndex()0111
Lexer.handleSign(char)151815
Lexer.isEnd()0111
Lexer.nextToken()0111
Lexer.parseNumber(int)3155
Lexer.preProcess(String)1122
Lexer.setIndex(int)0111
Lexer.tokenize()3013537
MainClass.findSingleEquals(String)6367
MainClass.main(String[])4155
MainClass.parseFuncDef(String)0111
Mono.Mono(BigInteger, BigInteger)0111
Mono.Mono(BigInteger, BigInteger, BigInteger, Poly)3123
Mono.Mono(BigInteger, BigInteger, Poly)3123
Mono.getCoeff()0111
Mono.getExpInner()0111
Mono.getXExp()0111
Mono.getYExp()0111
Mono.isSameType(Mono)6517
Mono.multiply(Mono)5145
Mono.negate()0111
Mono.withCoeff(BigInteger)0111
NumFactor.NumFactor(String)0111
NumFactor.toPoly()0111
Parser.Parser(Lexer)0111
Parser.isConditionWrapped()142712
Parser.parseChoiceFactor()1611515
Parser.parseDeriveFactor(String)4155
Parser.parseExpFactor()4155
Parser.parseExpr()9167
Parser.parseFactor()2211820
Parser.parseFuncCall()1821515
Parser.parseTerm(int)2133
Parser.setFuncDef(FuncDef)0111
Parser.setRecFuncDef(RecursiveFuncDef)0111
Poly.Poly()0111
Poly.Poly(int)0111
Poly.addMono(Mono)0111
Poly.addPoly(Poly)0111
Poly.derive(String)1122
Poly.deriveMono(Mono, String)225810
Poly.equals(Object)2210714
Poly.expToString(Poly)126511
Poly.formatSingleGroup(ArrayList, BigInteger)181614
Poly.hashCode()0111
Poly.isZero()0111
Poly.monoToString(Mono)131911
Poly.multiPoly(Poly)3133
Poly.negate()1122
Poly.polyToString(Poly)125610
Poly.powerPoly(BigInteger)6255
Poly.print()1222
Poly.simplify()10556
Poly.substitute(Poly)6144
Poly.subtractPoly(Poly)0111
RecursiveFuncCallFactor.RecursiveFuncCallFactor(RecursiveFuncDef, int, Factor)0111
RecursiveFuncCallFactor.toPoly()0111
RecursiveFuncDef.RecursiveFuncDef(Expr, Expr, BigInteger, Factor, int, BigInteger, Factor, ...)0111
RecursiveFuncDef.evaluate(int)15277
RecursiveFuncDefParser.expect(Lexer, Type)2133
RecursiveFuncDefParser.findSingleEquals(String)6367
RecursiveFuncDefParser.parse(String, String, String)2122
RecursiveFuncDefParser.parseCoeff(Lexer)2133
RecursiveFuncDefParser.parseRecurrence(String, Expr, Expr)131811
RecursiveFuncDefParser.skipUntil(Lexer, Type)3144
Term.Term(int)0111
Term.addFactor(Factor)0111
Term.toPoly()1122
Token.Token(Type, String)0111
Token.getType()0111
Token.getValue()0111
VarFactor.VarFactor(String)0111
VarFactor.toPoly()2122

我们可以发现整体项目代码的核心在于parser,lexerpoly这三个类,他们的主要作用分别是语法分析、词法分析和多项式处理。

经典度量分析

内聚度分析

总体来看,本次设计的代码架构属于高内聚情况。代码的高内聚比例达到了65%,其中主要的类都属于高内聚(Poly, Lexer, Parser, Mono, Token 等核心类);而中等内聚主要是一些拥有大量数据存储型属性的类,他的占比20% (RecursiveFuncDef, Expr, Term)。最后的低内聚占比约为15%,其中均为Factor的子类。

耦合度分析

入度*出度**扇出耦合强度
Poly92强(中心)
Parser28强(枢纽)
Lexer22
Factor110中(父类)
Mono51
Token20
Expr31
Term21

本次设计的代码的总体耦合度评估为中等。
我们代码中的主要耦合链如下:

MainClass 
  → Lexer(词法分析)
  → Parser(语法分析)
  → Expr → Term → Factor(表达式树)
  → Poly → Mono(计算核心)

而在Parser和各个Factor子类以及递归类之间的耦合则较弱。
总体来说,本次代码设计的主要耦合集中在了框架定义方面————词法-语法-语义。

二、项目架构

总体架构展示

┌─────────────────────────────────────────────┐
│         应用层:MainClass                    │
│      (输入 → 解析 → 计算 → 输出)           │
└────────────┬────────────────────────────────┘
             │
┌────────────▼────────────────────────────────┐
│   词法分析层(Lexer)& 语法分析层(Parser)  │
│   职责:String → Token序列 → 抽象语法树      │
└────────────┬────────────────────────────────┘
             │
┌────────────▼────────────────────────────────┐
│  语义处理层:Poly & Mono(数学计算核心)    │
│  职责:抽象语法树 → 多项式 → 结果输出        │
└─────────────────────────────────────────────┘

完整架构展示

img

架构处理过程展示


┌──────────────────────────────────────────────────────────────────────┐
│                          应用层:MainClass                            │
│                    负责整个流程的协调和结果输出                        │
└────────────────────────────┬─────────────────────────────────────────┘
                             │
┌────────────────────────────▼──────────────────────────────────────────┐
│                     第一层:词法分析(Lexer)                          │
│  ┌──────────────────────────────────────────────────────────────────┐ │
│  │ preProcess()  → tokenize()  → handleSign() → parseNumber()       │ │
│  │ (预处理)      (主要流程)     (符号处理)    (数字解析)             │ │
│  └──────────────────────────┬───────────────────────────────────────┘ │
│                             │                                          │
│                        String → Token[]                                │
└────────────────────────────┬──────────────────────────────────────────┘
                             │
┌────────────────────────────▼──────────────────────────────────────────┐
│                     第二层:语法分析(Parser)                         │
│  ┌──────────────────────────────────────────────────────────────────┐ │
│  │  parseExpr()                                                      │ │
│  │    ↓ (处理 + 和 -)                                               │ │
│  │  parseTerm()                                                      │ │
│  │    ↓ (处理 * 和 /)                                               │ │
│  │  parseFactor()                                                    │ │
│  │    ↓ (处理幂运算、括号、函数调用、三目表达式)                    │ │
│  │  Factor 多态调度(13个子类)                                     │ │
│  │    - NumFactor / VarFactor / ExpFactor                           │ │
│  │    - FuncCallFactor / DeriveFactor / ChoiceFactor               │ │
│  │    - RecursiveFuncCallFactor / ...                              │ │
│  └──────────────────────────┬───────────────────────────────────────┘ │
│                             │                                          │
│                    Token[] → Expr → Poly                              │
└────────────────────────────┬──────────────────────────────────────────┘
                             │
┌────────────────────────────▼──────────────────────────────────────────┐
│              第三层:表达式结构(Expr → Term → Factor)               │
│  ┌──────────────────────────────────────────────────────────────────┐ │
│  │  Expr                    Term                    Factor           │ │
│  │  ├─ List<Term>          ├─ List<Factor>        ├─ abstract       │ │
│  │  ├─ addTerm()           ├─ addFactor()         ├─ toPoly()       │ │
│  │  └─ toPoly()            └─ toPoly()            └─ setIndex()     │ │
│  └──────────────────────────────────────────────────┬────────────────┘ │
│                                                      │                  │
│  Factor.toPoly() 递归调用 Term.toPoly(),                             │
│  Term.toPoly() 递归调用 Factor.toPoly()                              │
└────────────────────────────┬──────────────────────────────────────────┘
                             │
┌────────────────────────────▼──────────────────────────────────────────┐
│              第四层:函数管理(Function & Recursion)                  │
│  ┌──────────────────────────────────────────────────────────────────┐ │
│  │  FuncDef                    RecursiveFuncDef                      │ │
│  │  ├─ name: String            ├─ base0, base1: Expr               │ │
│  │  ├─ body: Expr              ├─ cache: HashMap<Int, Poly>        │ │
│  │  ├─ call(Poly)              ├─ evaluate(int n)                  │ │
│  │  └─ substitute()            └─ 记忆化优化(O(2^n)O(n))      │ │
│  │                                                                    │ │
│  │  FuncCallFactor ──→ FuncDef.call()                               │ │
│  │  RecursiveFuncCallFactor ──→ RecursiveFuncDef.evaluate()        │ │
│  └──────────────────────────────────────────────────────────────────┘ │
└────────────────────────────┬──────────────────────────────────────────┘
                             │
┌────────────────────────────▼──────────────────────────────────────────┐
│          第五层:数学计算核心(Mono & Poly)【关键层】               │
│  ┌──────────────────────────────────────────────────────────────────┐ │
│  │  Mono(单项式)                    Poly(多项式)                │ │
│  │  ┌────────────────────────────┐   ┌─────────────────────────┐   │ │
│  │  │ • coeff: BigInteger        │   │ • monos: List<Mono>    │   │ │
│  │  │ • xexp: BigInteger         │   │ • addPoly()            │   │ │
│  │  │ • yexp: BigInteger         │   │ • multiPoly()          │   │ │
│  │  │ • expInner: Poly ★★★      │   │ • simplify()           │   │ │
│  │  │                            │   │ • derive()             │   │ │
│  │  │ 方法:                      │   │ • powerPoly()          │   │ │
│  │  │ • multiply()               │   │ • substitute()         │   │ │
│  │  │ • isSameType()             │   │ • toPoly() / print()   │   │ │
│  │  │ • withCoeff()              │   │                        │   │ │
│  │  └────────────────────────────┘   └──────┬──────────────────┘   │ │
│  │                                           │                      │ │
│  │                  ◆ 递归关系(关键创新):                        │ │
│  │          Mono 中的 expInner 指向 Poly                           │ │
│  │          Poly 的 monos 包含 Mono                                │ │
│  │          这形成了自然的递归结构,支持 exp 无限嵌套 ◆           │ │
│  └──────────────────────────────────────────────────────────────────┘ │
│                                                                        │
│  运算示例:                                                            │
│  • exp(x) → Mono(1, 1, Poly{x})                                      │
│  • exp(exp(x)) → Mono(1, 0, Poly{Mono(1, 1, Poly{x})})              │
│  • (x+1)^2 → Poly{Mono(1,2), Mono(2,1), Mono(1,0)} → simplify      │
└────────────────────────────┬──────────────────────────────────────────┘
                             │
┌────────────────────────────▼──────────────────────────────────────────┐
│                   输出:格式化字符串(toString())                     │
│            • 动态规划优化:公因式提取                                 │
│            • 缓存机制:避免重复计算                                   │
└──────────────────────────────────────────────────────────────────────┘

优点:架构清楚明了,支持多次的迭代和优化,将整个代码分成了三大板块,各自分工明确。
不足Pasrser的语法分析过于冗长,Factor子类过多

架构新迭代情形展望

三、项目架构设计过程

一、第一次作业:基础架构(仅支持加减乘幂,变量仅x)

第一次作业我采用了三层架构来处理多项式表达式。将字符串通过逐层解析转化为多项式对象,再进行数学运算。

数据结构: 简单的系数-幂次映射

HashMap<Integer, Integer>
key: x 的幂次
value: 该项的系数

解析器: 递归下降解析

Expr → Term → Factor
按优先级处理加减、乘法、幂运算

计算层: Poly 类统一处理所有运算

  • addPoly():多项式加法
  • multiPoly():多项式乘法
  • powerPoly():多项式幂运算

评价:架构清晰简洁,但 无法表示 exp(x) 这样的项,限制了功能扩展。

二、第二次作业:底层重构(支持 exp、函数、三目表达式)

第二次作业需要支持 exp 嵌套、函数定义等复杂需求,原有的 HashMap 数据结构无法满足。我引入了 Mono 类 来表示更复杂的项,改用 ArrayList<Mono> 存储,并为 exp 运算添加了新的方法。

核心改进:Mono 类的递归设计

class Mono {
    BigInteger coeff;        // 系数
    BigInteger xexp;         // x 的幂次
    Poly expInner;          // exp 内部的多项式(递归!)
}

在这里我使用了递归结构:在Mono 中包含 Poly,而 Poly 是 List<Mono>,形成了自然的递归关系。这样我们就可以表示任意深度的 exp 嵌套了。
同时我也需要重新设计几个运算逻辑,例如:

  • isSameType():判断同类项时需要比较 exp 内容,不仅仅是幂次.
  • multiply():两项相乘时,exp 相乘遵循规则 exp(u)·exp(v) = exp(u+v).
  • simplify():合并同类项需要考虑 exp 信息.

最后我新增了内容以便支持这次迭代:用于支持函数定义和调用的Function 类;用于处理函数调用因子的FuncCallFactor;以及处理三目表达式 的ChoiceFactor;最后是处理 exp() 函数的ExpFactor

评价:保留了第一次的架构框架,通过新增 Mono 类和改变存储方式优雅地扩展了功能。但 ArrayList 的顺序存储导致合并同类项时需要 O(n²) 的复杂度,性能有所下降。不过这个设计足够稳定,为第三次作业的扩展奠定了坚实基础。

三、第三次作业:功能完善(支持递推函数、导数,新增变量 y)

第三次作业不需要在底层进行重构,他只需要在第二次稳定的数据结构基础上,进一步扩展运算功能。我新增了 RecursiveFuncDef 类独立处理递推函数,在 Poly 类中添加 derive() 方法处理导数运算,同时支持了 y 变量。

核心设计

  • 递推处理RecursiveFuncDef 类用 HashMap 缓存计算结果,实现记忆化优化
  • 导数运算:在 Poly 层面分解链式法则,最终拆分为基本的加减乘运算
  • 变量扩展:Mono 中新增 yexp 字段存储 y 的幂次

评价:在不改动底层数据结构的前提下,通过设计新类和扩展已有方法优雅地实现了新功能,体现了第二次重构设计的成功。

总结

三次作业的迭代过程比较流畅,主要问题在于用ArrayList去储存,这导致了代码性能方面的下降。

四、Bug 分析

自己代码中的 Bug

问题 1:符号解析逻辑过于集中

现象:第二次作业中,Lexer 的 handleSingle 方法对于前导符号和运算符号的解析存在混乱,导致某些符号组合无法正确处理。

根本原因handleSingle 方法职责过重,试图在一个方法中处理多种不同的符号场景。

解决方案:引入 preProcess() 前置处理方法,负责预先对相邻符号进行合并和化简,然后再将规范化后的 token 流传入 handleSingle。这样通过分工明确的两个方法替代了一个臃肿的方法,提高了代码的可维护性。

问题 2:大指数运算溢出且性能差

现象:计算多层嵌套的指数时,指数的数值超出了int存储范围,同时计算速度太慢。

解决方案:我把将指数改用 BigInteger 存储,支持任意大小的指数,同时相应的修改了相关方法;同时在指数计算时采用了快速幂算法,将时间复杂度降至 O(log n)

他人代码中发现的问题

虽然没有搭建完整的测评机,但通过分析同学代码,我发现了一些规律性的问题:

第一次作业:主要问题集中在符号组合处理上,特别是在连续符号的识别。我针对这类场景构建了测试数据。

第二、三次作业:主要问题出现在函数运算大规模展开后的项合并上。在函数递推或乘法展开后,如何正确识别和合并同类项成为关键。

总体而言,我在互测过程之中发现的实质性 bug 并不多,这反映出大多数同学代码的基础实现是正确的。不过这也让我意识到搭建完整的自动化测评机确实是必要的,能够系统地发现边界情况和性能问题。

五、优化

自己代码中的优化

1. 三目表达式的解析

对于 [condition ? exprA : exprB],
根据 condition 的结果只解析需要的分支,
跳过不需要的另一分支的解析
→ 减少不必要的计算

2. 输出优化(toString 方法)
通过动态规划和公因式提取,优化输出字符串的长度。例如,3x + 6x + 9x 可以输出为 3(x + 2x + 3x) 或直接合并为 18x

3. 递推函数的记忆化缓存
使用 HashMap 缓存已计算过的递推值,避免重复计算。时间复杂度从 O(2^n) 降至 O(n)。

六、大模型使用

对于大模型的使用率估计(独立计算)

序号正确性性能
第一次作业5%10%
第二次作业10%30%
第三次作业10%0%

大模型的主要使用场景:第一次作业中的输出序列优化;第二次作业中的动态dp算法以及三目运算中项的分解;第三次作业递归函数的计算。

其余应用场景

  • 在同房互测环节,我使用了AI来为我讲解同学代码的大致思路,并且详细了解优化和计算的逻辑。
  • 在本次博客作业之中,我让AI为我辅助生成了一些表格和流程展示。

使用效果

对于代码的优化部分,大模型完成的很好,我的动态dp算法由大模型生成,同时,我的递归函数计算过程也由大模型指导,在这两个小模块代码之中,大模型的完成效果显著。
对于寻找bug环节,大模型实现的效果并不理想,很多时候会虚构出一些bug或者构造不符合输入原则的序列。

七、心得体会

在本次作业中,我自己最大的体会就是底层代码的重要性和性能对于代码影响的重要性。由于在第二次作业的时候为了方便而使用了ArrayList去存储Mono,我的代码在性能方面一直处于劣势,而这一错误也一直在我的代码中贯穿,直到总结时才发现自己的问题。
同时,明确自己代码的架构对于程序的构建也至关重要。在多次的迭代之中,我们需要抓住本质的架构,在修改方法、增加变量、增改类的繁琐工作之中,只有掌握好自己代码的框架,在每次迭代之前明确自己的修改范围和方法,才能够保证自己的改进能够完整而正确。

八、未来方向建议

可以在第一次作业时在指导书之中加入对于代码架构设计的指引,这样可以让同学们不用在之后的迭代中反复推倒重建自己的代码架构。

...全文
30 回复 打赏 收藏 转发到动态 举报
写回复
用AI写文章
回复
切换为时间正序
请发表友善的回复…
发表回复
内容概要:本文针对低温环境下微电网运行中电池寿命损耗加剧的问题,提出了一种考虑电池寿命的优化调度模型,并通过Matlab代码实现仿真验证。研究聚焦于低温导致电池性能下降、循环寿命缩短的技术挑战,结合分布式能源出力波动性与负荷需求变化,构建了融合经济性、可靠性与电池健康状态的多目标优化调度框架。通过引入电池老化成本模型,将寿命损耗量化为可调度变量,优化充放电策略以延长电池使用寿命并降低系统综合运行成本。文中详细阐述了目标函数设计、约束条件设定及求解方法,并通过算例分析验证了该策略在抑制深度充放电、均衡电池组使用、提升系统经济性等方面的有效性。; 适合人群:具备电力系统、新能源或优化算法基础知识的研究生、科研人员及从事微电网、储能系统相关工作的工程技术人员。; 使用场景及目标:①应用于高寒地区或冬季低温场景下的微电网能量管理系统设计;②为研究电池寿命与系统经济性之间的权衡关系提供建模思路;③作为Matlab优化工具箱(如Yalmip、CPLEX)在电力系统调度中应用的学习案例; 阅读建议:读者可结合文中提供的Matlab代码,复现仿真结果,深入理解电池老化模型与优化调度的耦合机制,并尝试在此基础上引入更多不确定性因素(如电价波动、负荷预测误差)进行扩展研究。

309

社区成员

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

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