本文是BUAA OO课程Unit1在课程讲授、三次做业完成、自测和互测时发现的问题,以及倾听别人的思路分享所引发我的的一些思考的总结性博客。本文第二部分介绍三次做业的设计思路,主要以类图的形式展示,并有简单的优劣分析;第三部分为程序代码复杂度的分析(2、三两部分为基于度量的对本身程序结构的分析);第四部分为对本身、对他人程序的测试、DEBUG、Hack的思考;第五部分是分析做业中能够应用对象建立模式的可能性,和重构的思考。正则表达式
这三次做业我基本上采用了彻底不一样的方法,感受到其实很是有趣而且颇有收获。express
第一次做业的时候个人全部代码都在一个.class文件内,设计了一个没有什么意义的主类Derivation,包含了一个多项式类和一个单项式类。这种设计除了在文件管理上不容易丢失文件之外基本没有什么好处。第二次和第三次做业中代码才愈来愈面向对象。第三次中有一些体现抽象工厂的设计,使用了Factor接口和Item抽象类,显然第三次做业的程序更具备可扩展性。实际上我在第二次做业中就有意识地在下降模块的耦合以方便单元测试。数组
第二次和第三次的做业实际上采用了不一样的设计思路,主要在于第二次是为了提升对输出优化处理的可扩展性,第三次是为了提升支持输入的项的类型的可扩展性。第二次中的对象保存的是对一个多项式的各类处理方法,而第三次的对象保存的是多项式的各类组成成分。这两个程序一个在怎么处理产品的方法上有较好扩展性,一个在能处理的产品种类上有较好扩展性。此外,第三次做业我尝试直接使用字符串来保存数据,无心中使用了Creative Pattern。前两次做业中,会牵涉到对象的拷贝等,容易发生错误,某些对象的方法可能不具备可再现性,引入不安全性而且不利于单元测试;第三次做业中,因为没有计划作详细的优化,使用了直接进行字符串操做的简化设计,但很是不利于优化。此外,前两次做业使用的容器还较为传统(定长数组),不利于利用现有的包进行合并同类项优化而本身写了优化的方法,虽然实现简单,可是也浪费了空间资源。安全
从三次做业来看,代码结构的基本复杂度、模块复杂度和圈复杂度呈现明显的逐次降低趋,体现出个人程序更加结构化、模块化,这有利于代码的理解和结构化、模块化的维护、测试和功能扩展;各模块之间耦合度下降,有利于模块的隔离、维护和复用;程序独立路径的数量也在减小,则出现错误的概率会下降,亦有利于测试和维护。模块化
123 "|\\d+)[ \t]*)*[ \t]*";
123 "|\\d+)[ \t]*)*+[ \t]*";
47 boolean canOptimizeWith(Monomial m) { 48 return ((this.power.equals(m.power) && 49 (this.sinPower.equals( 50 m.sinPower.add(new BigInteger("2"))) 51 && m.cosPower.equals( 52 this.cosPower.add(new BigInteger("2")))) 53 || (this.cosPower.equals( 54 m.cosPower.add(new BigInteger("2"))) 55 && m.sinPower.equals(this.sinPower.add(new BigInteger("2"))))))); 56 }
48 return (this.power.equals(m.power) && 55 this.cosPower.add(new BigInteger("2")))
47 public void optimize() { 48 if (super.getData().matches(".*\\^0*1")) { 49 setData(getData().replaceAll("\\^0*1", "")); 50 } else if (super.getData().matches(".*\\^0*")) { 51 setData("1"); 52 } 53 }
47 public void optimize() { 48 if (super.getData().matches(".*\\^0*1")) { 49 setData(super.getData().replaceAll("\\^0*1", "")); 50 } else if (super.getData().matches(".*\\^0*")) { 51 setData("1"); 52 } 53 }
我互测中遇到的BUG主要是对数据的输入处理的问题,例如未判断正负号使用是否正确就先去除了重复的正负号,或者在正则表达式中使用“\s”从而引入了不容许的特殊字符的可能性,或者某些位置应该容许输入多个空格只容许了单个。还有对不完整的输入,好比“+x+”,"45*"等没有进行判断。第三次做业中,还有同窗没有使用BigInteger处理数据,或者对指数为000000000000000000001的输入进行了报错,说明这方面没有处理得当。还有对于如“x*+1”的乘法内含有带符号整数因子处理错误的状况。函数
主要经过阅读代码针对性测试和构造测试数据盲测结合进行测试。JUnit的Series可以排列组合生成一些数据,同窗分享的随机生成字符串也能生成数据,但主要仍是人工设计的边界条件数据或者特殊状况数据更容易测出错误。在时间容许的状况下,阅读代码是最有效的找到别人BUG的方法。固然,本身设计时积攒或出错过的测试数据也有使用的价值。单元测试
What Information测试 |
More Information | Less Information |
Trail优化 |
Step by stepthis |
Conditional Breakpoints |
Code |
The whole code |
Coverage |
Value of variables |
Variables |
Watches/Evaluation |
Exception |
Throw an exception |
... |
Anything |
Hiearchy + |
Hiearchy - |
我认为DEBUG也是值得思考的事情。DEBUG是根据提供的信息寻找所写代码中错误并改正的过程。经过IDEA和Eclipse所支持的丰富的功能,咱们能够轻易的得到包括代码覆盖、变量值、代码轨迹等信息,经过增长和减小信息结合本身程序的设计结构,能够大大减小锁定bug的时间。利用条件断点实现分级的DEBUG信息输出也是有价值的DEBUG方法。
第一次做业中,我没有实现多项式类,将多项式当作多个单项式存储在数组中进行处理,并编写相应的各类方法。能够重构,设计多项式类,仅包含HashMap类,并且因为多项式求导后仍是多项式,求导方法可使用new的方法返回一个多项式。
第二次做业中,也没有实现多项式类。仍可设计多项式类,各类多项式处理器与主函数的数据交流也能够重构为对象建立的方法,每次返回一个new多项式,可使得各类求导、优化、合并同类项、根据三角函数公式优化等方法能够独立地开发和测试。
第三次做业我已经有使用工厂模式的影子,仍有不少能够改进的地方。能够完成部分优化工做,这里就须要注意equals方法的重写以支持合并同类项。此外,在我设计中使用了替换字符以屏蔽括号内正负号和乘号的处理方法来应对多层嵌套,分割后再将字符换回,这个有很大的不安全性,也能够重构,将这种乘积和单项式匹配方法(即递归地根据+、*分割输入)改成expression tree对象的处理,改成工厂模式,能够减小正则表达式的使用和避免对输入数据的改动引发的不安全性。