BUAA-OO第一单元总结

顾檬-19373765 2024-03-23 19:55:25

本次作业共包含三次迭代:

  • 第一次实现了包含加、减、乘、乘方、单层括号的表达式处理
  • 第二次实现了嵌套括号处理、自定义函数处理、指数函数处理
  • 第三次实现了表达式求导与自定义函数嵌套

作业过程中的主体思路为递归下降算法,还包含有诸如字符串替换、SOLID法则的一些小细节,具体处理过程如下:

预处理:对表达式字符串进行预处理。

构造语法树:采用递归下降算法。

  1. 第一层递归:分析表达式中的项(以+、-为分隔)。
  2. 第二层递归:分析项中的因子(以*、^为分隔)。
  3. 第三层递归:分析因子。
  • 表达式因子:若为带括号的表达式或指数函数,回到第一层。
  • 自定义函数因子:应用字符串替换后,回到第一层。
  • 求导因子:调用求导方法后,回到第一层。
  • 幂函数/常数因子:返回相应多项式给第二层。

性能优化:进行相关的化简处理。

hw1

设计思路

 

在此次的程序开发中,我采用递归下降分析法。这是一个较为普遍采纳的框架。此框架核心理念在于对输入的表达式进行抽象分层,细分为表达式、项以及因子三个级别。具体来说,表达式是由项构建的,项又是由因子构成。在具体的处理过程中,采用递归的方法逐级深入,直至因子级别,依据需要处理的因子类型采取相应的解析策略,并在解析完成后返回该因子,至此一次递归过程完毕。

这种架构相比直接对字符串进行正则表达式解析,在多个方面都显示出显著的优势。首先,它具备较高的容错性和可读性,每一个层级的行为都清晰可见,出错时也能较容易定位到问题所在的具体层级和方法。此外,这种框架不容易引入细节错误,能够有效规避许多难以通过常规测试发现的小问题(例如,在字符串解析中需要细致考虑符号顺序等复杂细节,而递归下降方式能够自动处理许多此类问题)。其次,代码的可扩展性极强,对于大多数新增需求,通常可以通过增添新的因子类型来应对。对于类似嵌套括号这样的问题,甚至无需额外处理,因为该架构已经自然包含了对嵌套结构的处理能力。

类图

Begin:程序入口,顺序调用读入、词法分析、语法分析等功能。

Lexer:词法分析器。

Parser:语法分析器。

Syntax:接口,代表树节点,以下类均实现该接口。

Expr:  表达式类。

Factor:因子类,下属常数因子、变量因子、表达式因子三个子类。

Term:项类。

Poly:多项式,即Mono的集合。

Mono:单项式,为输出的基础单位。

Token:词法分析的结果,语法分析的基础单位。

TokenType:Enum类。

在表达式、项、因子、单项式、多项式类中均实现toPoly()方法,将其归纳为单项式集合,输出时递归调用即可。

代码复杂度分析

Statics

如图所示,总体复杂度控制在一个可以接受的范围。

 

Class Metrics

词法、语法分析器与表达式类复杂度较高。表达式类中实现了表达式合并的功能,两个分析器中判断逻辑较多。

优化策略

程序在调用词法分析器前对读入的字符串进行了空格与正负号的预处理,但根据架构本身,这是一项多余的优化工作。

 

hw2

设计思路

 

在hw1的基础上,hw2引入了对嵌套括号、自定义函数以及指数函数的支持,是一个相对复杂的迭代过程。如同之前所述,递归下降架构展现出了其出色的可扩展能力,在本次迭代中尤为明显。首先,对嵌套括号的支持已经在第一次作业的框架中被顺利实现。接着,对于自定义函数和指数函数这两种新的因子类型,实际上我们所需做的,仅仅是增加两个实现了Factor接口的新类。

然而实际操作过程却充满挑战。在实现自定义函数的过程中,笔者的初版方案为对自定义函数定义节点进行深克隆,之后用克隆出的新节点替换掉语法分析器中的自定义函数调用节点。然而,由于hw1中深克隆功能的不完善,导致这一方案出现了严重bug——以至于需要重构框架。这种情况下,进行字符串层面的替换成为了更简单的方案。

类图新增

FuncDef:自定义函数定义类。

SelfFun:自定义函数调用类。

代码复杂度分析

Statics

 

Class Metrics

 

 由于代码重构工作量较大,未能通过第二次作业。

hw3

设计思路

 

第三次作业基于exp2进行了重构,对整体架构进行了精简,不再严格按照格式化表述进行类的创建与管理,转而把项、表达式等抽象的递归关系具象成具体的基础因子单项式,如“单项式乘积”、“单项式加和”等结果。

对于新增的求导因子的功能,将dx操作视为与exp操作本质相同的运算符,在对应的toString()输出方法、derive()求导方法中进行相应修改。

这样的架构设计有较强的可扩展性,例如面对迭代场景:若要增加对积分的支持,只需将积分也视为一种运算符,修改\增加相应方法作修改即可。

 

类图重构

代码复杂度分析

Statics

 

Class Metrics

 如图所示,Term类与Parser类的复杂度较高。其中Term类的复杂度较高是因为Term类实现了链式法则求导、乘法分配律、项的合并化简等运算操作,代码量较大。Parser类为语法分析器,判断逻辑较多,复杂度较高。

 

...全文
117 1 打赏 收藏 转发到动态 举报
写回复
用AI写文章
1 条回复
切换为时间正序
请发表友善的回复…
发表回复
wujizeze 老师 2024-04-21
  • 打赏
  • 举报
回复

应把类图放上来,便于阅读和理解你的架构设计思路

301

社区成员

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

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