2026 面向对象设计与构造 第一单元总结

何炫熠-24371385 2026-03-29 10:59:34

一、程序结构分析

1. 总体架构

 

 

自我点评:

  • 优点:

    • 职责划分较为清晰,不会出现功能交叉,耦合度相对较低,各部分独立运行

    • 核心计算类设计利好直接合并同类项,实现起来比较简单

  • 缺点:

    • Function、RecFunction 直接进行文本替换,容易被嵌套复杂结构影响或者是卡住,此外没有抓住二者共性,代码重复度较高

    • 计算类较为臃肿,扩展性较差

    • Mono 类实际只用来解构输出,可能将部分 Poly 权责下放 Mono 会更加优美

2. 总体代码规模与宏观数据

本次项目的宏观度量数据如下(以下数据部分为经过 Lizard 工具对项目全局扫描,使用 AI 工具整理形成):

类名 (Class)总规模 (NLOC)方法数 (Func Cnt)平均方法规模 (Avg.NLOC)平均圈复杂度 (Avg CCN)
Poly2631913.03.4
Lexer2201513.95.3
Coefficient183198.92.3
Variable143168.22.0
Parser131815.03.9
RecFunction68511.83.0
Mono62413.23.8
Simplifier5258.42.4
MainClass48143.06.0
Term3756.21.8
Expr3674.11.3
Function2745.51.5
Factory2335.01.0
Total1293111--
Avg-8.5310.52.9

分析

  • 整体而言,类的方法数控制在 5 ~ 15 个 的合理范围,平均方法规模在 5 ~ 15 行 内,平均圈复杂度在 1.0 ~ 3.0 内,说明整体内聚性和耦合度控制得比较合理

  • 处于平均视角之外:PolyCoefficientVariableLexer 承担了相当多的功能,以 Lizard 给出的指标:```

    !!!! Warnings (cyclomatic_complexity > 15 or length > 1000 or nloc > 1000000 or parameter_count > 100) !!!!

    说明这些类设计得相当臃肿,扩展性和可读性相对较差

  • 控制分支:

    !!!! Warnings (cyclomatic_complexity > 15 or length > 1000 or nloc > 1000000 or parameter_count > 100) !!!!
    ================================================
      NLOC    CCN   token  PARAM  length  location
    ------------------------------------------------
          40     22    293      1      40 Lexer::preOperation@42-81@./src\Lexer.java
          51     19    334      0      52 Lexer::next@147-198@./src\Lexer.java
    ==========================================================================================

    Lexer 由于控制分支过多,触发了警告,不过似乎这也是没办法的事情?或者我们可以将一些判断再细分出一些方法,这样可以增强可读性。如果需要进一步优化,应该再分析这些条件分支的共性,进一步抽象,可以减少圈复杂度

3. 类的内聚与相互间的耦合情况分析

内聚性分析

  • 高内聚模块ExprTerm 作为表达式树的节点,只负责维护自身的数据结构和基础的合并逻辑,方法极短(平均 4-6 行),职责极其单一,体现了极好的信息内聚Simplifier 将化简逻辑独立出来,也体现了较高的功能内聚。

  • 低内聚风险(上帝类)Lexer 类不仅负责了字符串的遍历 (next, skipIf),还负责了预处理 (preOperation) 和函数展开 (expandFunctions)。这违反了单一职责原则,导致该类既长又杂,内聚度下降。

耦合性分析

  • 不可避免的结构性耦合Parser 强耦合于所有的语法树节点(Expr, Term, Factor 等),因为它需要实例化这些对象,这是递归下降解析器的固有特征。

  • 良好的解耦尝试:我引入了 Factory来统一管理变量和因子的创建。这有效地将 Parser 和具体的底层数据类型进行了解耦,当需要增加新的变量类型时,只需修改工厂,符合开闭原则。

  • 数据依赖耦合Poly Coefficient, Variable之间由于存在大量的数学运算,它们的方法互相调用频繁,且互相作为参数传递。这种业务逻辑上的紧耦合是相对合理的,但是难以解开,扩展性差。

二、架构设计体验

 

这是我第一次作业的架构,在第二次作业仅仅只是引入了新的元素,没有进行较大改动,但是在第三次作业,我将很多 Factor 类去掉了,原因在于即使我实现了它们,计算时仍然总是用 getPoly() 来工作,既然如此直接用 Poly 不就好了 ,因此,我的重构策略如下:

  1. Parser 将诸多 Factor 直接解析为 Poly (通过工厂类),不再显式地创建因子类,减少无用结构

  2. 将预处理的部分实现转移到 Simplifier ,并把化简式子整体功能用 Simplifier 实现,既可以在运行过程中使用,也方便测试

扩展可行性分析:

  1. 不可拆函数:例如三角函数,可以类比 exp 封装到 Coefficient

  2. 新的自变量:例如 z ,我的 Variable 类使用 HashMap<String,BigInteger> 实现从变量名到指数的映射,因此添加不难

  3. 积分:只考虑单独的幂函数不难,如果配合指数函数貌似数学上有困难(?)

总体来说,由于使用了相应的保管类,加东西是可行的,但是 Key 值的复杂化可能会导致 HashMap 性能下降,导致超时

三、BUG分析报告

hw1: 空白项需要包含 '\t' ,x^0的特判处理

hw2: 没有跳过选择式因子中不需要解析的那个因子,导致TLE

hw3: 优化做错,导致多加了长度

出现这些问题往往是因为开发周期较长,以至于具体细节实现时忘记应该考虑的事情,容易顾此失彼。

此外,经过对比分析可以发现,有问题的方法圈复杂度较高,需要进行很多情况的考虑。

我认为后续的设计可以采用以下方式减小错误:

  1. 每次作业前先整体的列出架构,从正确性和性能两个方向考虑,最好形成文字

  2. 控制单个类的规模,并针对每个方法及时写测试,保证每个类内局部最优

  3. 尝试合并条件分支,简化逻辑

四、互测策略

采取了评测机对拍 + AI分析 + 重点观察核心类的方法

评测机(开源链接)的数据来源于自己拍脑袋想出来的一些边界数据和随机脚本生成的数据,允许将互测房间内所有人的程序 zip 同时测试,根据自定义规则筛选出不同的答案,可以初步确定一些情况

AI分析环节主要是让 AI 快速总结项目架构,便于快速地掌握整体

重点观察环节则是根据个人理解,对于自己容易错或者认为对方架构可能哪里出错的地方进行重点观察,并针对具体原因设计样例

例如: 在 hw3 中,因为我自己是采取先把所有的 f 进行替换,然后再进行解析计算的策略,但是后来想到选择式因子不需要解析不符合的因子,而展开也需要时间,这个问题在hw2或许不太明显,因为 f 只有单层的,只需要注意解析时跳过即可,但是hw3可能会出现展开之后变得很长的因子,即使我们直接跳过不解析它,也会因为展开延误了时间。

而我在互测房间里发现和我一样做法的同学。

以下是我构造的样例:

1 f(x) = (2x^2+10x+779) ^4 0 [(1==1)?1:f(f(f(f(f(f(f(f(f(f(f(f(f(f(f(f(f(f(f(f(f(f(f(f(f(f(f(f((x+y)))))))))))))))))))))))))))))]

五、优化策略

  1. 缓存: 由于主体采用 HashMap ,而构造 hash 需要一定时间,因此在复制时将 hash 值一并克隆,可以减少重复构造的开销。此外 toSting() 、递推函数也采用了缓存,加快速度

  2. 长度: 将正项提前,省略 1* / ^1 ,将 exp(0) 等同于 1,判断 exp 内是否需要加额外的括号

  3. 快速幂: 为了计算更迅速,采用快速幂

事实上,我的优化并不总能带来最好的结果:

  • 快速幂在常数上比较好用,但是对于多项式来说大头反而是底数的自乘,例如底数本身是个 x+1 ,如果是依次乘入,只需要处理简单的系数,而如果使用快速幂,则乘入时的项将非常复杂,性能上可能更差

  • exp()的指数并不总要乘到括号里,有时候提出来反而会更简洁

经过交流,我有一些初步的想法:

例如,计算exp(inside)inside 的最大公因数,提取出来作为指数或许能得到更好的结果

六、我与大模型

 正确性AI率性能优化AI率
hw120%30%
hw230%50%
hw340%70%

完成作业的过程中,正确性方面(也即完成主要内容)使用 AI 主要是进行代码补全(例如对方法名称的补全),提高效率;性能优化方面主要是用 AI 不断完善,添加一些修补性的优化代码

其他方面,在辅助找 bug、评测机搭建、博客作业等方面都使用过 AI 进行。

下面对大模型的效果总体评价一下:

  • 上下文长度是最明显的瓶颈,长文本任务降智比较严重(如找bug,需要阅读整个项目进行理解)

  • 对于局部性任务,或许相对而言比较好,但不一定与其他组件适配(例如它很难理解为什么解析选择式因子需要跳过其中一些部分)

  • 对于博客作业,生成的文字味道比较重,很难说跟本人风格相像

发现别人使用大模型的痕迹:

  • 注释十分详尽的,一看就是

  • 变量名、方法名、类名比较长的(长到已经有多余的单词),有嫌疑

七、心得体会与未来方向

本单元的学习继承了先导课的知识,整体上能比较充分地考虑架构设计,实现课上课下结合,掌握了面向对象思想的部分内容,学会如何根据实际需求合理建类、分配方法和属性,形成一套完整的开发流程(整体设计——代码实现——功能测试)

希望未来的第一单元课程能够设置更多样化的元素,使课程内容更丰富

八、思考题

1. 输入合法性检验

题目给出了准确的设定形式化表述,我们可以将其中所有的元素(包括空白项)进行建模,通过解析器解析来判断是否符合格式,例如

对于表达式 → 空白项 [加减 空白项] 项 空白项 | 表达式 加减 空白项 项 空白项

parseExpr():
    hasHead = false
    Expr expr = new Expr();
    while(1):
        if (lexer.end()):
            return ture
    
        if (!hasHead):
            if isBlank(lexer.peek()):
                expr.add(makeBlank())
                lexer.next()
            if isPlusOrSub(lexer.peek()):
                expr.add(makePlusOrSub())
                lexer.next()
            if isBlank(lexer.peek()):
                expr.add(makeBlank())
                lexer.next()
        else:
            if isPlusOrSub(lexer.peek()):
                expr.add(makePlusOrSub())
                lexer.next()
            else:
                return false
            if isBlank(lexer.peek()):
                expr.add(makeBlank())
                lexer.next() 
        if parseTerm(): 
            hasHead = true  
        else:
            return false
        if isBlank(lexer.peek()):
            expr.add(makeBlank())
            lexer.next() 

按照形式化表述严格处理即可

2. Cost的计算

1. 输入合法性检验 中,类似的解析方法不仅能检测出异常成分,而且在解析过程中会建立相应的成分实例,最终计算 cost 时,每个类会计算自己的cost,然后上层类根据相应的规则结合起来

3. 一些其他的思考

对于多余括号的判定,可以写一个返回因子数的方法,当括号里的因子数多于1时,即认为是表达式

...全文
145 回复 打赏 收藏 转发到动态 举报
写回复
用AI写文章
回复
切换为时间正序
请发表友善的回复…
发表回复
第1章课程定位与教学案例综述. 1.1职业岗位能力需求分析 1.2课程设置和课程定位分析 1.3WebShop电子商城介绍 1.3.1电子商城需求分析 1.3.2电子商城系统设计 1.3.3电子商城数据库设计 1.4LibraryMIS图书管理系统介绍 1.4.1图书管理系统需求分析 1.4.2图书管理系统系统设计 1.4.3图书管理系统数据库设计 习题 第2章面向对象技术和建模基础 2.1面向对象方法 2.1.1面向对象方法的基本思想 2.1.2面向对象方法的发展 2.2面向对象的基本概念与特征 2.2.1面向对象的基本概念 2.2.2面向对象的主要特征 2.3面向对象分析 .2.3.1处理复杂问题的原则 2.3.200A方法的基本步骤 2.4面向对象设计 2.5面向对象实现 2.6面向对象方法的内涵 2.7软件建模概述 2.7.1软件建模的概念 2.7.2软件建模的用途 2.7.3软件建模的优点 习题 第3章UML简介 3.1UML的发展 3.1.1UML的发展历程 3.1.2理解UML建模 3.2UML的特点 3.3UML的结构 3.3.1UML的事物 3.3.2UML的关系 3.4UML的视图 3.4.1用例视图 3.4.2逻辑视图 3.4.3并发视图 3.4.4组件视图 3.4.5部署视图 3.5UML图形符号 3.5.1用例图 3.5.2类图 3.5.3对象图 3.5.4状态图 3.5.5活动图 3.5.6顺序图 3.5.7协作图 3.5.8组件图 3.5.9部署图 3.5.10UML 2.0新特性 3.6UML建模基本流程 习题 第4章UML建模工具简介 4.1常用UML建模工具 4.1.1 Rational Rose 4.1.2Enterprise Architect 4.1.3Together 4.1.4PowerDesigner 4.1.5 Visi0 4.1.6Tnffun Plat0 4.2Rational Rose安装与配置 4.2.1Rational Rose的运行环境 4.2.2Rational Rose的安装 4.2.3Rational Rose的配置 4.3使用Rational Rose建模 4.3.1Rational Rose主菜单 4.3.2Rational Rose的视图 4.3.3 Rational Rose建模的基本过程 习题 第5章需求建模 5.1用例模型概述 5.2用例图组成 5.2.1参与者 5.2.2系统 5.2.3用例 5.3识别和描述用例.. 5.3.1识别用例 5.3.2绘制WebShop电子商城用例图 5.3.3通过包对用例进行合理规划 5.3.4WebShop电子商城用例图(不含关系) 5.3.5用例描述 5.4用例间的关系 5.4.1泛化关系 5.4.2使用关系 5.4.3包含关系 5.4.4扩展关系 5.4.5关系小结 5.4.6WebShop电子商城用例图(含关系) 习题 第6章静态建模 6.1静态建模概述 6.2类图概述 6.3类图的基本组成 6.3.1类的概述 6.3.2绘制带属性的实体类 6.3.3绘制带操作的实体类 6.3.4绘制边界类图 6.3.5绘制控制类图 6.3.6UML中的类与语言中的类 6.4类之间的关系 6.4.1关联关系 6.4.2聚合关系 6.4.3组合关系 6.4.4泛化关系 6.4.5实现关系 6.4.6依赖关系 6.5对象图 6.5.1对象图概述 6.5.2对象图组成 6.5.3类图和对象图的比较 习题 第7章数据库建模 7.1PowerDesigner简介 7.2PowerDesigner安装和启动 7.2.1PowerDesigner的安装 7.2.2PowerDesigner的启动 7.3PowerDesigner概念数据模型 7.3.1概念数据模型概述 7.3.2PowerDesigner概念数据模型概述 7.4 PowerDesigner物理数据模型 习题 第8章动态建模 8.1动态建模概述 8.2状态图 8.2.1状态图概述 8.2.2状态图组成 8.2.3绘制员工下班回家状态图 8.3活动图 8.3.1活动图概述 8.3.2活动图组成 8.3.3绘制WebShop电子商城活动图 8.4活动图拾遗 8.4.1活动图与流程图的比较 8.4.2活动图与状态图的比较 8.5顺序图 8.5.1顺序图概述 8.5.2顺序图组成 8.5.3绘制WebShop电子商城顺序图 8.6协作图 8.6.1协作图概述 8.6.2协作图组成 8.6.3绘制WebShop电子商城协作图 8.7 顺序图拾遗 8.7.1 顺序图与协作图的比较 8.7.2 顺序图与协作图的互换 习题 第9章物理建模 9.1物理建模概述 9.1.1硬件 9.1.2软件 9.2组件图 9.2.1组件图概述 9.2.2组件图组成 9.2.3绘制WebShop电子商城组件图 9.3部署图 9.3.1部署图概述 9.3.2部署图组成 9.3.3绘制WebShop电子商城部署图 习题 第10章双向工程 10.1双向工程简介 10.2正向工程(生成Java代码) 10.3逆向工程 习题 第11章统一软件过程RUP 11.1RUP简介 11.2RUPT作流程 11.2.1业务建模 11.2.2需求 11.2.3分析设计 11.2.4实施 11.2.5测试 11.2.6部署 11.2.7配置与变更管理 11.2.8项目管理 11.2.9环境 11.3RUP迭代过程 11.3.1初始 11.3.2细化 11.3.3构造 11.3.4移交 11.3.5迭代计划示例(构造阶段) 习题 附录A综合实训 附录B Rational Rose2003主菜单 参考文献...

302

社区成员

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

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