面向对象设计与构造 第一单元总结
面向对象设计与构造 第一单元总结
代码分析
第一次作业
总体架构
Main类负责读取输入的表达式及输出求导后的结果,Expression类负责解析输入的表达式,然后并将其转换为Term类存进value为Term的Hashmap中,Term类存储每一项的系数和指数。
度量分析
方法度量分析
| method | CogC | ev(G) | iv(G) | v(G) |
|---|---|---|---|---|
| Expression.delete(String) | 0 | 1 | 1 | 1 |
| Expression.derivative() | 10 | 1 | 6 | 7 |
| Expression.Expression(Stirng) | 34 | 1 | 16 | 17 |
| Main.main(String[]) | 0 | 1 | 1 | 1 |
| Term.derivative() | 10 | 5 | 8 | 8 |
| Term.getCoe() | 0 | 1 | 1 | 1 |
| Term.getExp() | 0 | 1 | 1 | 1 |
| Term.setCoe(BigInteger) | 0 | 1 | 1 | 1 |
| Term.setExp(BigInteger) | 0 | 1 | 1 | 1 |
| Term.Term(BigInteger,BigInteger) | 0 | 1 | 1 | 1 |
类的度量分析
| class | OCavg | OCmax | WMC |
|---|---|---|---|
| Expression | 6.33 | 12 | 19 |
| Main | 1.00 | 1 | 1 |
| Term | 1.67 | 5 | 10 |
![]() |
类图分析

- Main
Main只负责表达式的输入和求导结果的输出。
![image]()
- Term
保存表达式每一项化简后的系数和指数,derivative方法将项求导后的表达式以String形式返回。
![image]()
- Expression
负责处理输入表达式,利用正则表达式将输入表达式拆分为一个个的项,然后将每一项进行化简存进Hashmap中。
delete方法负责对输入表达式进行预处理,删除多余空格以及将多个符号进行化简。
derivative方法遍历Hashmap,分别调用Term的derivative方法,最后将结果以String的形式返回。
![image]()
优缺点分析
优点
- 代码整体架构简单,代码逻辑整体较为清晰。
- 识别、求导实现解耦,可以快速定位BUG位置。
缺点
- 使用正则表达式处理表达式,难以快速修改其造成的处理问题。
- 类过少,识别、求导过程仅面向由项组成的表达式,可拓展性差。
第二次作业
总体架构
MainClass负责表达式的输入和求导结果的输出;Reduction利用递归下降的方法对输入表达式进行化简;Expression负责对表达式进行处理;Key为Expression中Hashmap的key值,用于简单的同类项合并;Term存储项的系数和指数。
度量分析
方法度量分析
| method | CogC | ev(G) | iv(G) | v(G) |
|---|---|---|---|---|
| Expression.containsKey(HashMap(Key,Term),Key) | 3 | 3 | 2 | 3 |
| Expression.derivative() | 11 | 1 | 6 | 8 |
| Expression.Expression(ArrayList(Stirng) | 26 | 1 | 9 | 9 |
| Expression.getCoe(String[]) | 5 | 3 | 2 | 3 |
| Expression.getCosExp(String[]) | 13 | 5 | 1 | 5 |
| Expression.getExp(String[]) | 14 | 5 | 2 | 6 |
| Expression.getSinExp(String[]) | 13 | 5 | 1 | 5 |
| Expression.getValue(HashMap(Key,Term),Key) | 3 | 3 | 2 | 3 |
| Expression.reSymbol(String) | 0 | 1 | 1 | 1 |
| Expression.xPlace(String[]) | 3 | 3 | 2 | 3 |
| Key.equals(Key) | 1 | 1 | 3 | 3 |
| Key.getCosExp() | 0 | 1 | 1 | 1 |
| Key.getSinExp() | 0 | 1 | 1 | 1 |
| Key.getExp() | 0 | 1 | 1 | 1 |
| Key.Key(BigInteger,BigInteger,BigInteger) | 0 | 1 | 1 | 1 |
| Key.setCosExp() | 0 | 1 | 1 | 1 |
| Key.setSinExp() | 0 | 1 | 1 | 1 |
| Key.setExp() | 0 | 1 | 1 | 1 |
| MainClass.main(String[]) | 0 | 1 | 1 | 1 |
| Reduction.getExpression() | 27 | 1 | 11 | 12 |
| Reduction.getFactor() | 30 | 8 | 14 | 16 |
| Reduction.getNewExpression() | 0 | 1 | 1 | 1 |
| Reduction.getTerm() | 50 | 4 | 15 | 17 |
| Reduction.Reduction(String) | 0 | 1 | 1 | 1 |
| Reduction.reExpression() | 0 | 1 | 1 | 1 |
| Reduction.reSymbol(String) | 0 | 1 | 1 | 1 |
| Term.derivative() | 22 | 1 | 8 | 11 |
| Term.derResult() | 57 | 2 | 23 | 25 |
| Term.getCoe() | 0 | 1 | 1 | 1 |
| Term.getExp() | 0 | 1 | 1 | 1 |
| Term.getCosExp() | 0 | 1 | 1 | 1 |
| Term.getSinExp() | 0 | 1 | 1 | 1 |
| Term.setCoe(BigInteger) | 0 | 1 | 1 | 1 |
| Term.setExp(BigInteger) | 0 | 1 | 1 | 1 |
| Term.setSinExp(BigInteger) | 0 | 1 | 1 | 1 |
| Term.setCosExp(BigInteger) | 0 | 1 | 1 | 1 |
| Term.Term(BigInteger,BigInteger) | 0 | 1 | 1 | 1 |
类的度量分析
| class | OCavg | OCmax | WMC |
|---|---|---|---|
| Expression | 4.30 | 9 | 43 |
| Key | 1.00 | 1 | 8 |
| MainClass | 1.00 | 1 | 1 |
| Reduction | 5.00 | 14 | 35 |
| Term | 3.36 | 16 | 37 |
![]() |
类图分析

- MainClass
负责表达式的输入和求导结果的输出。
![image]()
- Reduction
将输入的表达式进行化简并将化简后的表达式分为一个个的项存进ArrayList中。
![image]()
- Expression
接收由Reduction生成的ArrayList,并将其中的项进行处理化为Term存进Hashmap中。
![image]()
- Key
作为Expression中Hashmap的Key值,存储该项的指数,正弦函数的指数和余弦函数的指数,用以进行同类项合并的判断。
![image]()
- Term
由于第二次作业中只加入了正余弦函数和表达式嵌套,因此经过Reduction化简后的项都可以用axbsinc(x)cosd(x)表示,因此在第一次作业的基础上在Term里加入sinExp和cosExp,这样就可以存储一个项所有的内容了,在求导时增加对正余弦函数的结果生成。
![image]()
优缺点分析
优点
- 求导过程比较简单,只需要根据求导后的指数构建相应的表达式即可。
- 可以利用Key进行简单的同类项合并。
缺点
- 只针对本次作业进行Term类的构建,可拓展性差。
- Expression内对表达式的处理较为复杂。
第三次作业
总体架构
由于最初未能想出处理三角函数中表达式嵌套的方法准备放弃这次作业,但是却在周六晚睡觉前想到了一种做法,于是通宵写了出来,总体架构于第二次作业没有太大变化,由于时间问题,未能想出比较好的判断输入格式是否正确的方法,仅仅针对中测中出现过的错误格式进行了判断,并将这些判断写在了MainClass中。
度量分析
方法度量分析
| method | CogC | ev(G) | iv(G) | v(G) |
|---|---|---|---|---|
| Expression.derivative() | 11 | 1 | 6 | 8 |
| Expression.Expression(ArrayList(Stirng) | 101 | 5 | 22 | 27 |
| Expression.getCoeX(String[]) | 2 | 2 | 1 | 2 |
| Expression.getCosExp(String[]) | 20 | 6 | 3 | 7 |
| Expression.getExp(String[]) | 14 | 5 | 2 | 6 |
| Expression.getSinExp(String[]) | 20 | 6 | 3 | 7 |
| Expression.getStr(String) | 11 | 1 | 7 | 7 |
| Expression.reSymbol(String) | 6 | 1 | 6 | 6 |
| Expression.xPlace(String[]) | 3 | 3 | 2 | 3 |
| MainClass.main(String[]) | 1 | 1 | 2 | 2 |
| MainClass.rightStyle(String) | 54 | 16 | 21 | 27 |
| Reduction.getExpression() | 27 | 1 | 11 | 12 |
| Reduction.getFactor() | 58 | 8 | 21 | 23 |
| Reduction.getNewExpression() | 0 | 1 | 1 | 1 |
| Reduction.getTerm() | 50 | 4 | 15 | 17 |
| Reduction.Reduction(String) | 0 | 1 | 1 | 1 |
| Reduction.reExpression() | 0 | 1 | 1 | 1 |
| Reduction.reSymbol(String) | 0 | 1 | 1 | 1 |
| Term.derivative() | 27 | 1 | 9 | 12 |
| Term.derResultCos() | 99 | 4 | 30 | 32 |
| Term.derResultSin() | 112 | 4 | 32 | 34 |
| Term.derResultX() | 71 | 2 | 23 | 25 |
| Term.getCoe() | 0 | 1 | 1 | 1 |
| Term.getExp() | 0 | 1 | 1 | 1 |
| Term.getCosExp() | 0 | 1 | 1 | 1 |
| Term.getSinExp() | 0 | 1 | 1 | 1 |
| Term.setCoe(BigInteger) | 0 | 1 | 1 | 1 |
| Term.setExp(BigInteger) | 0 | 1 | 1 | 1 |
| Term.addtSinExp(BigInteger) | 0 | 1 | 1 | 1 |
| Term.addSinExpression(BigInteger) | 0 | 1 | 1 | 1 |
| Term.addCosExp(BigInteger) | 0 | 1 | 1 | 1 |
| Term.addCosExpression(BigInteger) | 0 | 1 | 1 | 1 |
| Term.Term(BigInteger,BigInteger) | 0 | 1 | 1 | 1 |
类的度量分析
| class | OCavg | OCmax | WMC |
|---|---|---|---|
| Expression | 7.11 | 24 | 64 |
| MainClass | 9.00 | 17 | 18 |
| Reduction | 5.71 | 14 | 40 |
| Term | 6.62 | 23 | 86 |
![]() |
类图分析

- MainClass
负责表达式的输入和求导结果的输出,并且进行简单的格式判断。
![image]()
- Reduction
将输入的表达式进行化简并将化简后的表达式分为一个个的项存进ArrayList中。
![image]()
- Expression
接收由Reduction生成的ArrayList,并将其中的项进行处理化为Term存进ArrayLsit中。
与第二次作业不同的是,这次会将正余弦函数中所包含的表达式提取出来存进Term里。
![image]()
- Term
相比于第二次作业,为了处理正余弦函数包含的表达式因子问题,使用了ArrayList存储三角函数相关的数据,在求导时,会对cosExpression和sinExpression进行遍历取值,将其作为一个独立的表达式进行整个求导过程,包括进入Reduction和Expression,最后返回该表达式的求导结果,再与原本的sin或cos函数求导结果进行拼接,形成完整的求导结果。
![image]()
优缺点分析
这次的作业基本上算是一个赶工的半成品,很多地方都没有进行优化,对于输入数据的格式判断也没有进行完整的判断,求导过程中的判断也十分复杂,求导结果也没有进行化简,总体来说是一份失败的代码。
BUG分析
第一次作业
第一次作业中出现的BUG原因在于Expression中Hashmap的key值选取问题,强测代码中我选用输入顺序作为key值,但是这种方式会在后续合并同类项时发生问题,例如原本key值为3的项或因子由于合并同类项与key值为1的项进行了合并,而key值为4的项或因子可能与原本key值为3的项以乘法连接,这时搜寻key值为3的value将会失败,在修复过程中将key值换做了指数,解决了合并的问题。
BUG的出现位置为:Expression.Expression(String),复杂度较高。
第二次作业
第二次作业针对性较强,在强测和互测中未出现BUG。
第三次作业
第三次作业在强测中的BUG不出意料的是输入数据格式判断问题,此外还有输出结果的错误格式,即输出形式应为sin((-x))输出为了sin(-x),输出结果的错误格式是由于未能完全理解形式化表述,以为sin(-x)是合法格式。
BUG出现的位置为:Term.derivative(),复杂度较高。
HACK策略
自动评测机
利用python随机生成测试数据,再调用sympy进行测试。
重构经历总结
第一次重构
由于第二次作业出现了表达式嵌套,因此第一次作业中使用的正则表达式处理输入表达式无法使用,因此改变处理方法,利用递归下降将整体表达式化简并拆分为项,存进一个ArrayList中。
重构前:

重构后:

第二次重构
第三次作业中三角函数可以含有表达式因子,因此第二次作业Term无法进行相应的存储和求导,因此对Term进行了重构,使用ArrayList存储三角函数相关数据。
重构前:

重构后:

心得体会
第一单元作业使我深刻的意识到了一个拓展性好的架构是多么的重要,第一次作业使用正则表达式处理无法处理第二次作业的表达式嵌套,第二次作业对项整体的简化又无法满足第三次作业三角函数中的表达式因子问题,由于架构问题每次完成作业时都非常的困难,所以接下来的单元作业在开始写代码之前要想一个拓展性好的架构,避免一次又一次的大规模重构。
虽然第一单元作业完成情况并不理想,但也收获了很多知识,尤其是了解了Java一些数据结构的使用,正则表达式的用法和递归下降语法分析,在接下来的单元作业中也要继续努力,希望可以更好的完成单元作业。













浙公网安备 33010602011771号