一、三次作业总结
三次作业难度逐层递进,逐步帮助我们入门理解面向对象思想。第三次作业可以算是系列的巅峰版,因此本文重点介绍第三次作业的设计思路,当然前两次作业也进行了较细致的介绍。另外三次使用的查找bug方法较为相似,统一放在最后介绍。
1、 第一次作业
1.1 需求分析
1.2.2处理细节
本次表达式相对简单,但是因为输入字符串过长(200字符),用基于回溯的正则容易出现爆栈的问题,因此本次我进行了修改,去除了一开始使用大正则的思路,采用了循环处理的方法。即每次提取最靠前的项看是否匹配,然后删除最开始匹配到的部分,继续匹配。
另外,为了追求方便,我在开头进行统一特判,确定空格没有导致格式问题后去除空格,以便简化后续的处理。因为思虑补全这最后也导致我在互测的时候付出了惨重的代价,这个后续再说。
最后的优化中我采取了最基本的合并同类项思路,遗憾的是我没有考虑到将正项提前这件事,最后强测分没有满。
1.3 本次作业暴露的问题
1.3.1 测试问题
本次作业强测全对,互测有一个同质bug被抓。去空格时没有考虑到“x^+ 2”属于非法情况,即漏了"\\^[+-]\\d"这种非法情况。这也提醒我在接下来特判的过程中使用枚举记录的方法记录所有的信息,并使用手写脚本检验特判正确性。
1.3.2 结构问题
这次作业因为整体设计过于简单,个人感觉我的代码还是较为符合面向对象的设计需求的。结构没有太大问题。
1.4 本次作业的UML图和相关参数
UML图
参数分析
2、 第二次作业
2.1 需求分析
2.2.2处理细节
本次表达式复杂了些,但大体思路与上次接近,我仍采用了循环处理的方法。即每次提取最靠前的项看是否匹配,然后删除最开始匹配到的部分,继续匹配。
另外,为了追求方便,依然在开头进行统一特判,确定空格没有导致格式问题后去除空格,以便简化后续的处理。
在最后的优化过程中,我使用了下列技巧:
1、合并同类项
2、将正项提前
3、将a*cos^2*k+b*sin^2*k进行提取,进行一定判断化简为
2.3 本次作业暴露的问题
2.3.1 测试问题
吸取了上一次的教训,本次在特判空格的时候思维更加缜密,最终无论是强测还是互测都没有被发现问题。
2.3.2 结构问题
这次作业设计其实事后看已经开始给第三次作业做铺垫,变得复杂起来。本次作业其实已经可以使用继承和接口技巧来简化设计,但从上面的宏观设计图就可以看出我并没有使用接口和继承等技巧,导致最后的设计变得十分不简洁,不合理。很遗憾我一开始设计的时候没有考虑前面,没有把握住Poly类和Derivate类的共性,误以为两个类差别很大,导致最后产生大量冗余设计,IDEA上产生大量黄线(代码完全复制导致),修改优化起来也变得复杂。
2.4 本次作业的UML图和相关参数
UML图
参数分析
类
方法
分析:从参数图可以看出函数耦合程度过高,类也有很多重复嵌套,设计的并不是非常合理。我直到进行博客分析的时候才意识到这个问题,发现好多时候不应该直接把原始字符串扔进构造函数处理.....好吧,下次注意,做好准备,设计的更合理些
3、 第三次作业
3.1 需求分析
3.2.2处理细节
1、输入数据格式化:为了简化后续处理,本次作业一开始在简单判定合法性后就通过特判去除空格和连续重复的加减号了。这也使得我最后递归判断因子合法性时无需再对开头进行特判(如x因子,++x*3此时x前面两个加号合法,3*++x此时x前面两个加号不合法),也无需在子类中过度关注空格合法性这类非本质问题,从而更好地设计类的核心特性。
2、循环判断,使用堆栈思想提取出作为区分的加减号或是乘号。(见下图)
本次作业为了保证正确性,没有进行过多优化,但最后还是因为小疏忽发生了错误。
3.3 本次作业暴露的问题
3.3.1 测试问题
本次作业强测弱测都崩盘了。强测80分,互测中5刀,最后发现都是一个同质bug导致的,即在Poly类进行堆栈运算时我误将开始的部分由0写为1,导致处理括号嵌套的时候出现了问题。处理((((x))))这类的测试点没有问题,处理(((sin(x)+cos(x))))这类数据点则出现错误。而我这次测试时没有使用测试机,而是自己随手测了些数据,虽然也有括号嵌套的数据,但大多数较为简单并未涉及到bug发生处,导致最后酿成大祸。这次作业也提醒了我,必须得使用对拍器等自动化评测工具,避免出现这类问题,毕竟很多时候人自己测试往往会缺失随机性,很难设计出真正触及数据盲区的地方。
3.3.2 结构问题
这次作业的难度算是这一单元最高的了,不过经过前两次的作业锻炼之后我已经能够较好的处理这次作业了。本次作业我自认为设计的结构逻辑清晰,便于理解,架构挺漂亮的。具体实现细节也许有所欠缺,但整体设计方面问题不大。
3.4 本次作业的UML图和相关参数
UML图
参数分析
类
方法
二、查找别人bug策略分析
三次策略我采用的都是如下策略:
1、手动通过枚举设计WF类型数据
2、使用评测机随机生成正确格式的数据,检测计算错误
下面对1、2步进行具体分析
对于1来说,我在readme上列出了常见的由空格、多余正负号引起的WF数据各两个(如++++x,s i n ( x )等),然后列出了一些项连接及非法字符(\v\r...)导致的WF问题。最后统一进行测试。
对于2来说就是使用编写的评测机脚本利用xeger模块生成数据进行检测。
这种策略效果不错,在第一次,第二次都A屋的情况下仍然刀了5次左右。
三、第一单元学习整体总结
虽然第三次作业完蛋的一塌糊涂,但这个单元的学习还是让我很兴奋,感觉自己收获了很多。大一的时候看C++ primer plus的时候也接触过面向对象这个概念,但那时候因为自身编程水平较低,不得不过多关注于c++写class的语法而不是对象概念本身。而大二再接触面向对象时我的编程技术有了很大的增长,此时语言已不再是我的障碍,我可以更好地关注于面向思想本身。事实也的确如此。这三次作业其实并不是很难,但我依然得到了很大的提高。我学会了如何把握对象的数据和方法共性,并将共同点聚合成类。而且强测加互测这个制度也教会了我很多,让我开始反思自己的编程习惯。
从大一开始我就养成了这样一个不好的习惯:做完算法题直接交给评测机评测,评测机说有问题我就继续改,评测机说没有问题我就学习其他事情去了。事实上这个习惯是个很不好的习惯,毕竟评测机也不代表一定正确,而且实际工程中很多时候并没有评测机帮我们检验设计的产品效果。我们需要自己对程序进行仔细检查和雕琢才能设计出真正没有漏洞的程序。
第三次作业出结果后我有点难受,但不是因为分数,而是因为一种莫名的遗憾。第三次我真感觉自己设计的挺漂亮的,设计架构鲜明,类之间共性提取的也较好,具体实现事后听昂神宣讲发现有的地方还是不太严谨,但整体挺漂亮的。然后因为小疏忽导致程序出现了大bug,之前的设计全部成了水中月镜中花。毕竟代码美观整洁很重要,但归根结底一切的前提还是程序正确性本身。
我以后会加大自测强度,改变自己的设计习惯,塌下心来仔细雕琢自己的程序,力争不让这样的遗憾再次出现。
另外最近学习操作系统,看学校发的小型操作系统源码时候对一些c语法的使用产生了疑惑(比如说用双指针而不是单指针设计链表),不明白为何选择使用这种技巧实现而不是使用更常见的实现方式。上网查了查,偶然间看到了Linus老爷子对程序员的一些观点,然后恍然大悟。设计程序绝不是一个简单的机械工作,我现在感觉有时候设计程序就像是在实现艺术。希望自己以后能不断加深对程序设计的认识,加大对自己的要求,设计出思路更清晰,风格更简洁,功能更强大的程序。
附:
本次本人检查程序使用的插件为UML SUPPORT和MetricsReloaded,相关使用说明可以看pxc学长的博客:https://www.cnblogs.com/panxuchen/p/8689287.html
另外在看到pxc学长博客前我曾考虑用CK度量组对程序进行度量判断,这里需要用到的软件为sourcemonitor,使用链接一并附上:https://blog.csdn.net/yf210yf/article/details/17535713