OO第一单元
OO第一单元总结
基于度量的代码结构分析
第一次作业
架构分析
主类使用正则表达式输入项, 自定义的容器类存储项的次数与系数等信息
MainClass类:使用正则表达式提取项
Can类:存储项次数与系数, 进行求导计算与输出
UML类图

代码度量量统计
类与方法规模


类与方法复杂度


类与方法复杂度



设计评价
1.本次架构中没有使用到面向对象的继承与多态, 从某种意义上说只用到了面向对象的封装特性
2. 将大部分工作与任务集中到一个类Can上, 导致其复杂度高
3. 未对表达式进行元素对象的分析与抽象, 采用结构化模式, 不利于迭代开发.
4. 本设计存在的唯一优点是代码量少(100行)
第二次作业
架构分析
第二次作业采用表达式树的计算结构, 本质上是将输入表达式当作中缀表达式进行解析, j将+ - * sin cos (**)等符号看作运算符, 将x与常数视为操作数(原子表达式).
通过操作符将参与运算的原子表达式或中间表达式合并为另一中间表达式.此方法需要用栈来临时存储操作符与中间表达式, 因此构建了Stack类实现栈操作, Can类使用Stack
对象对多个中间表达式(Expression类对象)进行管理控制(分别实现运算sin cos + - * **的复合函数求导, 表达式合并),Expression类由Poly类(多项式)对象构成, 扩展了
加减乘计算方法, Poly类采用hashmap存储键值对<Term, Sitem(单项式)>, 便于同类项的合并操作. Term对象是对一个单项式特征的标识, 特征表示相同的对象可以提取公
因式合并, 实现化简
MainClass:主类负责输入表达式的预处理
Stack:栈容器, 将栈数据结构封装为一个Stack类, 以实现表达式树的计算
Can:容器类, 内含栈容器对象, 存储Expression类对象, 控制表达式Expression对象间的运算操作
Expression:表达式类, 由多项式对象构成, 实现表达式加减乘等运算求导方法
Poly:多项式类, 由多个单项式Sitem组成, 内部采用hashmap方式存储单项式对象
Sitem:单项式类, 表示一个单项式, 用于hashmap的Value
Term:表示一个单项式x sin(x) cos(x) 的次数统计用于hashmap的Key
UML类图

代码度量量统计



设计评价
1. 本次架构依托于数据结构中表达式树的算法, 因而结构化代码较多. 复杂度高
2. 虽然设计思路中体现了类与类之间的扩展包含关系, 但仍然没有采用继承方式实现.
3. 类之间采用组合方式(一个类的属性是另一个类对像应用)相互关联, 但其实可以利用继承实现, 组合关联反而带来了代码的冗余.
4. 因为采用表达式树的思想, sin cos都被视为函数操作符. 原子操作数只有x与常数,
因而整体表达式层次可以只需Sitem - > Poly -> Expression来表示, 不需要多构建sin(x) cos(x)对象.
5. Can容器与Expression中只用一个方法实现了算数运算与求导, 控制语句过多, 缺乏对方法的抽象.
6. 此架构具备了函数嵌套的求导, 利于第三次作业的增量开发.
第三次作业
架构分析
由于在第二次作业中实现了sin cos函数的复合求导, 因此只需在第二次作业基础上增量开发判断语法模式的类Syntax即可.(由于第三次作业只对第二次作业做了Syntax
类的扩充, 没有对原来的代码进行改动, 因此以下只对Syntax类做分析)
Syntax : 语法分析类
UML类图

Syntax代码度量量统计




程序BUG分析
第一单元三次作业强测与互测均没有发现BUG, 但经过对第三次作业的代码行数统计与圈复杂度度量, 发现程序复杂度还是挺大的, 可能有潜在的BUG存在且未被发现.
以下为互测被hack代码方法的圈复杂度与行数统计, 可以看出出BUG的方法圈复杂度较大行数相对较多.

在互测中阅读他人代码, 发现本单元作业易出BUG点:
1.未严格遵循形式化描述,对空白字符处理不到位
2.使用递推下降时没有考虑栈溢出
3.计算数字未全程采用BigInteger导致中间运算溢出
4.输出结果中括号嵌套不符合形式化定义
发现BUG的策略
1.采用随机数据测试代码, 但是随机数据一般不具有数据的特殊性, 能hackA屋中代码的样例一般都存在数据上的鲜明分布特点, 因此一般而言难以测出A屋中的BUG.
2.采用特殊构造针对性强的样例测试代码, 此种方式hack成功率高, 但是一般构造的数量少, 而且构造过程比较困难, 构造灵感一般在个人代码的编写或者讨论时产生.
3.大致浏览代码整体, 找到复杂度高的语段(可通过MetricsReloaded分析代码每个部分的复杂度), 通过仔细阅读分析或者猜测的方式了解该代码段的具体作用, 针对
此构造测试样例进行测试,本人使用策略的次数较少, 目前的尝试中还没有使用该策略hack成功的, 是否采用此方式取决于代码的简洁程度与空闲时间.
重构经历总结
第一次作业与第二次作业跨度较大, 因此重构在第二次作业是对第一次作业代码进行了重构(两次类图对比见下), 抛弃原先用正则表达式提取项的方式, 采用构
建表达式树的方式解析输入的表达式. 在层次结构上抽象出单项式Sitem, 多项式Poly, 表达式Expression等层次, 使用组合关系关联各类.

心得体会
本单元作业有一定难度, 一方面与算法相关, 另一方面与本人在编写代码的过程中缺乏面向对象的思想, 使得代码结构复杂不易debug. 因此从中得到教训, 要首先使用面
向对象的模式思考问题, 多学一些设计模式相关, 不要将问题的重点放在结构化的算法上.
浙公网安备 33010602011771号