OO第一单元总结——求导之旅
目录
- 程序结构分析
- 作业内容总结
- Bug评测分析
- 测试策略
- 采用的设计模式
一、程序结构分析
-
类图:
-
第一次作业:
第一次作业由于作业比较简单,自己也没有考虑以后的可扩展性问题,就只建立了两个类,Poly类进行输入格式的检查、字符串到对象的转换和求导运算, PolyCal类负责处理输入和输出。
因为求导结果仍为简单的多项式,因此并没有使用其他类和接口。 -
第二次作业:
第二次作业加入了
cos
和sin
函数,求导的结果相较于第一次也发生了变化,一些函数有着公共的特性。因此采用了继承以实现代码复用,使用接口实现多态。同时使用静态工厂来处理输入格式的检查和实 例化具体对象。 -
第三次作业:
第三次作业因为引入了
嵌套因子
的概念,因此原本第一第二次作业使用的正则表达式进行输入格式处理的方法无法继续沿用了。于是我在第二次作业的基础上增添了一个递归下降处理输入数据的类。同时增加了因子(Factor)
这一抽象父类实现多态。
第三次作业还使用了装饰者模式来进行递归求导。
-
-
度量:
-
第一次作业:
Class OCavg WMC poly.Poly 6.6 33 poly.PolyCal 2 2 Method ev(G) iv(G) v(G) poly.Poly.Poly(String) 5 2 6 poly.Poly.derivation() 1 2 2 poly.Poly.toBigIntegers(String) 1 6 10 poly.Poly.toPoly(ArrayList ) 1 4 4 poly.Poly.toString() 3 10 12 poly.PolyCal.main(String[]) 2 3 3 -
第二次作业:
Class OCavg WMC Cos 1.57 11 FormatModifier 4.2 21 Function n/a 0 FunctionTest 3 3 Monomial 1.9 19 Poly 3.83 23 Sin 1.57 11 Term 3.3 33 Method ev(G) iv(G) v(G) Cos.Cos(BigInteger) 1 1 1 Cos.Cos(String) 1 2 2 Cos.derivative() 1 1 1 Cos.getIndex() 1 1 1 Cos.isSimilar(Function) 2 1 2 Cos.multiply(Cos) 1 1 1 Cos.toString() 2 1 3 FormatModifier.FormatModifier() 1 1 1 FormatModifier.check(String) 5 2 6 FormatModifier.functionType(String) 5 4 5 FormatModifier.toFunctions(String) 2 3 6 FormatModifier.toTerms(String) 1 2 3 FunctionTest.main(String[]) 2 4 4 Monomial.Monomial(BigInteger,BigInteger) 1 1 1 Monomial.Monomial(String) 1 3 3 Monomial.add(Monomial) 1 1 1 Monomial.clone() 1 1 1 Monomial.derivative() 1 1 1 Monomial.getCoefficient() 1 1 1 Monomial.getIndex() 1 1 1 Monomial.isSimilar(Function) 2 1 2 Monomial.multiply(Monomial) 1 1 1 Monomial.toString() 1 5 8 Poly.Poly(ArrayList ) 1 2 2 Poly.Poly(String) 2 1 2 Poly.combine() 1 7 7 Poly.combineTri() 1 5 6 Poly.derivative() 1 3 3 Poly.toString() 1 2 4 Sin.Sin(BigInteger) 1 1 1 Sin.Sin(String) 1 2 2 Sin.derivative() 1 1 1 Sin.getIndex() 1 1 1 Sin.isSimilar(Function) 2 1 2 Sin.multiply(Sin) 1 1 1 Sin.toString() 2 1 3 Term.Term(ArrayList ) 1 2 2 Term.Term(String) 1 2 3 Term.add(Term) 1 2 2 Term.combine() 1 5 5 Term.derivative() 1 4 4 Term.isOptimizable() 2 2 3 Term.isSimilar(Term) 4 2 4 Term.multiply(Term) 1 3 3 Term.reverse() 1 2 2 Term.toString() 2 6 7 -
第三次作业:
Class OCavg WMC Cos 1.5 6 Factor n/a 0 Function 1 4 FunctionTest 1 1 InputHandler 3.81 61 Monomial 1.25 5 Num 1 5 Poly 1.6 16 PolyFactor 2.67 8 Sin 1.5 6 Term 3.2 16 Method ev(G) iv(G) v(G) Cos.Cos(BigInteger,Factor) 1 1 1 Cos.Cos(Num,Factor) 1 1 1 Cos.derivative() 1 2 2 Cos.toString() 1 2 2 Function.getIndex() 1 1 1 Function.getInnerFactor() 1 1 1 Function.setIndex(BigInteger) 1 1 1 Function.setInnerFactor(Factor) 1 1 1 FunctionTest.main(String[]) 1 2 2 InputHandler.InputHandler() 1 1 1 InputHandler.getNext() 2 2 2 InputHandler.hasNext() 2 1 2 InputHandler.input() 4 2 5 InputHandler.isNum(char) 2 1 3 InputHandler.isOperation(char) 2 1 3 InputHandler.pop() 2 2 2 InputHandler.toCos() 8 3 9 InputHandler.toFactor() 6 7 7 InputHandler.toMonomial() 4 3 5 InputHandler.toNum() 2 5 6 InputHandler.toOperation(char) 3 1 3 InputHandler.toPoly() 1 2 2 InputHandler.toPolyFactor() 3 4 6 InputHandler.toSin() 8 3 9 InputHandler.toTerm(boolean) 1 5 5 Monomial.Monomial(BigInteger) 1 1 1 Monomial.Monomial(Num) 1 1 1 Monomial.derivative() 1 1 1 Monomial.toString() 1 2 2 Num.Num(BigInteger) 1 1 1 Num.Num(String) 1 1 1 Num.derivative() 1 1 1 Num.negate() 1 1 1 Num.toString() 1 1 1 Poly.Poly() 1 1 1 Poly.Poly(ArrayList ) 1 2 2 Poly.Poly(Term) 1 1 1 Poly.add(Poly) 1 2 2 Poly.add(Term) 1 1 1 Poly.derivative() 1 2 2 Poly.getFirst() 1 1 1 Poly.size() 1 1 1 Poly.toFactor() 1 1 1 Poly.toString() 1 2 4 PolyFactor.PolyFactor(ArrayList ) 1 2 2 PolyFactor.derivative() 1 2 2 PolyFactor.toString() 1 2 4 Sin.Sin(BigInteger,Factor) 1 1 1 Sin.Sin(Num,Factor) 1 1 1 Sin.derivative() 1 2 2 Sin.toString() 1 2 2 Term.Term(ArrayList ) 1 2 2 Term.Term(Factor) 1 1 1 Term.derivative() 1 7 8 Term.negate() 1 1 1 Term.toString() 1 2 4
-
-
优缺点分析:
-
优点:
能够比较熟练地使用正则表达式进行字符串格式匹配。
能够使用继承实现代码复用和多态,使用接口实现多态。同时会使用一些设计模式以增强代码的可扩展性。
-
缺点:
虽然使用了一些设计模式来解耦,但是不同类之间的耦合度依然比较高,对这些设计模式的理解还不够深入。
同时,像处理优化这部分的内容,依然是使用面向过程的写法。
-
二、作业内容总结
这次作业需要掌握的,我认为有以下几点:
1.正则表达式的使用
2.类的封装
3.多态的使用(继承和接口实现)
4.可扩展性的代码
5.简单的设计模式
虽然看上去东西不多,但想要熟练使用,其实是很难的,比如可扩展性就需要对多态和封装的深入理解,以及一些设计模式的应用。
三、Bug评测分析
因为这三次作业我都写了自动化测试的脚本(Python),所以并没有出现Bug。
四、测试策略
我的测试策略是使用自动化评测机和数据生成器对Room的成员进行批量化测试。
第一、第二次作业直接使用Python中的Xeger包根据正则表达式生成正确的表达式(含合法的空白字符),之后随机插入合法和非法字符形成最终的表达式,用这个表达式来进行测试。能够覆盖各种合法和非法数据。
第三次作业则是使用递归下降的方法生成合法数据,对于数据中的项数、项中因子数、嵌套层数都是由参数控制的随机数。之后采用类似的随机插入的方法生成最终数据。
在第一次作业中,因为大家的代码都相对还比较短,我也有针对个人的代码构造测试样例,进行外科手术式的精准打击。但从第二次作业开始,大家的代码行数都开始急剧增加,我就只采用了自动化测试的方法进行评测。
五、采用的设计模式
第一次作业并没有明显的设计模式。
第二次作业使用了静态工厂方法,但仅仅在处理输入数据(字符串)的时候使用,算是一个跛脚的设计模式。
第三次使用了适配器模式,用于递归求导。在第二次作业中的Function抽象父类增加一个Factor类的成员变量以实现装饰,同时让Function类继承自Factor类,对求导方法进行修改后完成重构。