OO_unit1总结

苗汀昕-21371264 学生 2023-03-18 12:52:04

一、架构设计体验


结合三次作业的迭代介绍自己的架构如何逐步成型

hw1:基于training1的构建

在 training1 中我们实现了仅含有数字、括号、加法和乘法的表达式转化为后缀表达式,并结合课程组的经验分享,从而初步了解了递归下降的具体实现。对于第一次作业的要求,采用了 training1 的架构和层次,在处理上有如下方式:

  • 结合正则表达式的相关知识,删除或替换原始表达式中的空白符、连续的符号、幂次符号等,并将表达式和表达式因子开头的 + 删除, - 前补零,从而便于后续字符串解析。
  • 将 training1 中仅有的数字因子类替换为表达式因子类unit因子类,其中unit因子类可以表示常量因子和变量因子及其幂次,并统一使用Factor接口。
  • 由于表达式因子最后也可以解析为unit因子相运算,故可以用mono类来表示unit因子相乘所得到的单项式,用poly类表示单项式相加减形成的多项式。
  • 通过poly的相互运算,最终得到拆括号后的表达式,并通过poly类和mono类中toString方法的实现,将最终的表达式输出。

hw2:自定义函数的替换

第二次作业中增加了三角函数因子和自定义函数因子。

  • 对于三角函数因子,可以创建sinFactor类cosFactor类,用以表示内部有表达式因子、外部有幂次的三角函数因子。
    • 对于化简,由于三角函数内部并不会出括号,故可以作为表达式因子单独化简;
    • 同时类似第一次作业中合并同类项的方法,通过对该因子内部表达式因子是否相等的判断,用以实现三角因子同类项的合并化简。此时容易出现深浅拷贝的问题,可以重写hashCodeequals方法,也可以将内部表达式按一定规则排序后转化成字符串进行比较。
  • 对于自定义函数因子,创建Definer类,用以存储所有自定义函数的函数名与函数表达式、函数名与函数形参。
    • 在开始创建自定义函数的时候,存储函数相关的信息,并对函数表达式初步分析和化简,优化运算过程;
    • 同时考虑到后续调用时,如果直接用实参替换表达式中的xyz,容易造成函数形参与实参出现混淆,如 h(x,y) = x + 2*y,对于 h(y,2x) 就会因为重复替换出现 6*y 的错误结果。所以在一开始保存函数表达式的时候,就可以用不会出现在表达式中的符号直接替换其中的形参,如用 XYZ替换 xyz (注意不要用 abc 替换,因为 cos 中有 c )。
    • 在调用函数时,直接通过字符串操作,将形参替换为实参(注意加括号),再传入FuncFactor进行字符串的解析和结果保存。

hw3:求导功能的实现

第三次作业增加了函数嵌套调用和求导功能。

  • 由于使用的是递归调用的分析方法,函数嵌套调用已经基本实现。

  • 对于求导功能的实现,仍然在原有架构上,通过求导方法的实现来完成:

    • 对于Factor类增加求导的抽象方法diff()

    • 对于所有的因子(unit因子、三角函数因子、项、表达式),类比转化成多项式方法toPoly()的实现,根据求导公式重写diff()。这里我没有严格按照求导公式的递归来实现,而是根据不同因子的特点手动进行求导,例如:

      • 常量变量因子:a*x^b -> a*b * x^(b-1)

      • 三角因子:sin(in)^b -> b * sin(in)^(b-1) * cos(in) * dx(in)

      • term:遍历一下,其中一个因子求导后和其他因子相乘,将结果相加

      • 表达式因子:(expr)^n -> n * (expr)^(n-1) * dx(expr)

      • 表达式:term求导后相加即可

      • 为求导因子建一个类DiffFactor
        表达式解析的时候如果检测到求导因子如dx(expr),要得到其对应的多项式,即对内部表达式用diff()。后续操作就可以按照原有架构实现运算、输出字符串等等。

二、基于度量分析程序结构


根据代码度量分析工具Designite,度量类的属性个数、方法个数、每个方法规模、每个方法的控制分支数目、类总代码规模,得到类和方法的一些度量指标,具体如下:

方法表:

  • LOC (Lines Of Code - at method and class granularity) 代码行数

  • CC (Cyclomatic Complexity - Method)

    圈复杂度,用于衡量一个模块判定结构的复杂程度,圈复杂度越大说明程序代码质量低,且难以测试和维护。

  • PC (Parameter Count - Method) 方法中传入的参数个数

Project NamePackage NameType NameMethodNameLOCCCPC
oohomework_3exprCosFactorCosFactor412
oohomework_3exprCosFactordiff1921
oohomework_3exprCosFactortoPoly610
oohomework_3exprDiffFactorDiffFactor412
oohomework_3exprDiffFactortoPoly310
oohomework_3exprExprExpr310
oohomework_3exprExpraddTerm311
oohomework_3exprExprdiff721
oohomework_3exprExprtoPoly720
oohomework_3exprExprFactorExprFactor411
oohomework_3exprExprFactorsetIndex311
oohomework_3exprExprFactordiff1631
oohomework_3exprExprFactortoPoly310
oohomework_3exprFactortoPoly310
oohomework_3exprFactordiff311
oohomework_3exprFuncFactorFuncFactor412
oohomework_3exprFuncFactorfuntoExpr510
oohomework_3exprFuncFactordiff311
oohomework_3exprFuncFactortoPoly310
oohomework_3exprSinFactorSinFactor412
oohomework_3exprSinFactordiff1921
oohomework_3exprSinFactortoPoly610
oohomework_3exprTermTerm411
oohomework_3exprTermaddFactor311
oohomework_3exprTermdiff1751
oohomework_3exprTermtoPoly1130
oohomework_3exprUnitFactorUnitFactor513
oohomework_3exprUnitFactordiff1731
oohomework_3exprUnitFactortoPoly410
oohomework_3polyMonoMono814
oohomework_3polyMonoMono1222
oohomework_3polyMonogetCoe310
oohomework_3polyMonogetXexp310
oohomework_3polyMonogetYexp310
oohomework_3polyMonogetZexp310
oohomework_3polyMonoequals811
oohomework_3polyMonosinEqual1541
oohomework_3polyMonocosEqual1541
oohomework_3polyMonoaddSame311
oohomework_3polyMonomulTri2471
oohomework_3polyMonotoString51140
oohomework_3polyMonoaddXyz933
oohomework_3polyMonosetCoe311
oohomework_3polyPolyPoly310
oohomework_3polyPolyPoly411
oohomework_3polyPolyaddMono1951
oohomework_3polyPolyaddPoly1231
oohomework_3polyPolymulPoly2141
oohomework_3polyPolypowPoly1631
oohomework_3polyPolynegate520
oohomework_3polyPolytoString1550
oohomework_3tempDefineraddFunc2761
oohomework_3tempDefinercallFunc1122
oohomework_3tempLexerLexer411
oohomework_3tempLexersimplify2031
oohomework_3tempLexergetNumber1230
oohomework_3tempLexernext2780
oohomework_3tempLexerpeek310
oohomework_3tempParserParser311
oohomework_3tempParserparseExpr1530
oohomework_3tempParserparseTerm921
oohomework_3tempParserparseFactor1750
oohomework_3tempParserparseDiff710
oohomework_3tempParserparseFuncFactor1221
oohomework_3tempParserparseSinCosFactor1831
oohomework_3tempParserexprFactor1120
oohomework_3tempParserunitFactor2430
oohomework_3(default package)MainClassmain1721

类表:

  • NOF (Number Of Fields) 域个数
  • NOM (Number Of Methods) 方法个数
  • LCOM (Lack of Cohesion in Methods - Class) 方法的内聚缺乏度
  • FANIN (Fan-in - Class) 类调用的上级模块的个数
  • FANOUT (Fan-out - Class) 类直接调用的下级模块的个数
Project NamePackage NameType NameNOFNOPFNOMNOPMLOCWMCNCDITLCOMFANINFANOUT
oohomework_3exprCosFactor203333401003
oohomework_3exprDiffFactor202211201001
oohomework_3exprExpr104423601042
oohomework_3exprExprFactor204430601013
oohomework_3exprFactor00208270-160
oohomework_3exprFuncFactor204319401004
oohomework_3exprSinFactor203333401003
oohomework_3exprTerm2044391000023
oohomework_3exprUnitFactor303331501001
oohomework_3polyMono6014141684200072
oohomework_3polyPoly1088982400082
oohomework_3tempDefiner202242800023
oohomework_3tempLexer3054711600040
oohomework_3tempParser10971192200035
oohomework_3(default package)MainClass001119200-105

分析类的内聚和相互间的耦合情况:

秉承着高内聚低耦合的思想,LCOM的值越小越好,FANIN和FANOUT与复用性和复杂度有关,视情况判断好坏。

其中Factor类的FANIN值较高,说明其复用性较好;LCOM值普遍较低,说明代码基本符合高内聚低耦合的设计要求;FANOUT值中MainClass和Parser的值较高,因为其中进行各个模块的调用导致复杂度较高。

由各个方法的代码行数和圈复杂度可以看到,字符串相关处理和输出函数的复杂度最高,其次是各种因子计算函数和求导函数。这是由于在字符串输出过程中使用了大量的判断以实现最终表达式的化简。

画出自己作业的类图:

img

  • 使用了Factor抽象类来作为接口,在此基础上延伸出普通因子类(常量和变量因子)、三角因子、函数因子等等。
  • Definer用于函数的解析和调用,保存函数的定义式和形参列表。
  • Parser和Lexer用于解析表达式,将原始表达式一步步从expr、terms拆分到不同类型的factors。
  • mono实现不同因子的表示和输出为字符串。已解析表达式的因子中的toPoly实现转化为多项式,并在Poly类中实现多项式的运算。

三、BUG分析


  • 在第一、二次作业中,由于利用了大量字符串的判别和处理用以化简,实际上导致了lexer类和因子的toString方法显得有些臃肿,逻辑不是很清晰,故而产生了许多奇奇怪怪的bug,如负数识别等。同时许多同学涉及到了对0次幂的化简问题,常见bug如0**0

  • 第二次作业中涉及到类引用问题,常见bug如(sin(x)**2+cos(x)*sin(x))**2。对类引用问题,可以使运算方法全部new一个对象,不再改变原有因子的状态。

  • 在第三次作业中,我们可以手动构造三角因子、函数因子、求导因子相嵌套的数据,尝试临界值如0、-1等,尤其是函数因子实参、求导处容易出现bug。

  • 出现了bug的方法一般会在化简步骤上,这部分并没有固定的逻辑方法,很多时候大家都是慢慢补充条件判断的,代码行和圈复杂度上自然更高。

四、心得体会


第一星期体验了一把四天速通java,开始艰难地理解递归下降,一行一行代码都要问问百度(泪)。

代码大体结构是站在了前人的肩膀上,读了很多学长学姐的博客,终于大致理解了先解析后计算的逻辑思路。一方面由于前期想不通逻辑迟迟没有开始写hw1导致最后时间不够;另一方面通过再次和同学交流得到了我认为还算不错的架构,方便了后面两次作业的完成,同时也大大降低了出bug的可能性。

后面两次工作虽然繁琐,但是思路都比较清晰,所以完成起来也有一定的规划,不再疯狂压ddl了。

关于互测,个人反思构造数据时候太依赖自己的错误来造数据,并没有更多的面向组内成员的代码对症下药。研讨课上也学到了很多构造的逻辑和方法,希望下次在这方面可以更进一步。

...全文
39 1 打赏 收藏 转发到动态 举报
写回复
用AI写文章
1 条回复
切换为时间正序
请发表友善的回复…
发表回复
诸彤宇教师 教师 2023-03-24
  • 打赏
  • 举报
回复

第二次作业中涉及到类引用问题
————类引用?对象引用?二者概念是不一样的

444

社区成员

发帖
与我相关
我的任务
社区描述
2023年北京航空航天大学《面向对象设计与构造》课程博客
java 高校 北京·海淀区
社区管理员
  • 被Taylor淹没的一条鱼
  • 0逝者如斯夫0
  • Mr.Lin30
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

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