一、前言
本单元的故事可以理解为:“多写少想闭门造车的血泪”。下文均围绕此主题展开。
二、基于度量来分析自己的程序结构
1.第一次作业
由于我并没有预料到将来作业的重构方向,于是当时留下的所谓“扩展接口”,后来都有点沦为无稽之谈。
第一次作业还算是完全在我的能力范围之内,经过pre的初步磨练,我选择了Treemap来维护整个多项式,依靠指数做key来做合并。
这之后会令多项式的合并变得简单。
几个类的维护也算比较满意,基本上做到了合适的分工,故而没有出现复杂逻辑和过长的类。
由于Term的处理放在构造中,该方法比较复杂。
2.第二次作业
第二次作业,由于时间安排不够合理,我的开工时间偏晚。为了实现何冰同类项,我仍然采取了与第一次方法类似的方法来构建表达式。只是这次的vaue维护的是由<系数,幂函数指数,sin指数,cos指数>构成的四元组。
这次也写了关于sin^2+cos^2=1 的化简部分,但由于种种考虑,并未提交。
此外,这次的求导方法写得不大通用,故而为下次重构埋了隐患
复杂度分析:
3.第三次作业
第三次作业生动展示了一个取巧到了尽头的选手是如何迎来火葬场的——虽则从work1.2文件夹复制了所有的文件,可是Makeitem以外的部分事实上都删掉重写了……
大体思路是:把求导过程看成一个表达式求值的过程,在对个别特殊字符做处理后,就只需按照运算法则来实现求导过程了。和传统的表达式计算不同的地方在于,表达式求导在后续过程中也可能需要原式,故而需要原式的结果。
这里就有了初步的架构:一个poly需要两个栈来实现表达式计算的过程,之后对于item,需要维护其tostring(保存原式)和todiff(保存求导结果)两个方法。
而compute类,则负责所有计算结果的生成。
这一部分的基本设想还是基本做到了划分层次的,但之后却因为构造栈的具体想法不够清晰而导致细节问题过多,最终makestack方法惊人,颇有我在第一次作业时默默吐槽过的“一main到底”风范。(当时还“祝愿”.java.c 选手后面完蛋,结果我却先转型.java.c且完蛋了)。
此外,compute类在做无谓优化时,导致部分格式错误,这一点也是出于考虑不够仔细的问题。 相比起来,我的WrongFormat虽则面向过程色彩浓厚,但胜在层次清晰。是一部分我写完后便有自信说“没问题”的可贵模块。这一块,将isPoly,isTerm,IsItem做了三级划分,分别利用简单的符号拆分和正则表达式就完成了构造。如若这样清晰的构造可以继承,那么我的程序也许会好不少。
这里有自己的几点改进尝试:makeitem和makeopr方法,前者其实可以并入makeitem工厂(事实上,makeitem类会在运行后期完全闲置),而后者逻辑简单,可以尝试放入compute类。
可以看到,最可怕的就是面向过程的polynomial类,尤其是它的“一main到底”色彩的makestack
三、分析自己程序的bug
1.
第一次没有bug。
2.
第二次作业则由于空白字符未考虑出错。
3.
第三次作业由于细节较多,产生了bug。
分别是错误的括号处理和错误的运算法则。
错误的括号处理:
- 在cmobi运算中,会因表达式无括号不被判定为因子而WF。
- 在poly预处理中,认为头尾的括号必然是一对,而导致(x+1)*(x+2)会被错误的去括号。
运算法则:
在combi里有错误的化简规则,会导致结果错误(但在互测和强测中未被测出,明明x*cos(0)就卡掉了)
四、分析自己发现别人程序bug所采用的策略;
第一次作业让我对随机测试对拍效果产生怀疑,故而没有着手准备复杂的自动化测试手段。
主要是通过对特殊样例的构造来实现的。
事实上,我的错误均可以通过简单样例捕获。
但相对地,人力有所不逮,大量的数据构造也更容易发现问题,且解决相应困难。
所以自动化测试还是有必要的。
五、应用对象创建模式来重构
事实上,我的第二次作业使用的还算是“工厂”。
而第三次作业的面向过程色彩过于浓厚,工厂基本被架空,可以算是打包出去的方法而已,因为如前文所述,其主要功能被makeitem方法取代了。
第三次作业虚伪地使用了第二次作业的遗产,然而只是让旧的结构掣肘而已,这是不应该的。而第二次作业中还算不错的poly--term--item三层结构却完全失去效力。这一点实在是不可理喻。
六、对比和心得体会。
我仔细阅读了第一次和第三次的几份代码。相对而言,我第一次作业还是不错的,模块划分,方法长度,命名规范做得都不错。不过还是可以看到一些同学在细节处理上的巧思。
而第三次代码则由于我的架构混乱,导致我在过程中一直被反复吊锤,每一行都在提醒我:你结构太烂啦!
总结前文,有如下地方需要改正:
- 工厂方法过于简陋(只能生成几种基本项,还是暴力if),导致其功能被架空。
- 设计不足,面对较为复杂的内容没有做好层次划分(第三次作业事实上只有原来基础上改写的几个item类有分层次感觉)
- 抽象问题,最突出的表现第三次作业,Item类本质就是存储两个字符串,导致后期也无法优化。
几点心得:
这次作业开场后,惨淡结尾。
直接原因在于:时间安排不合理。我的工作基本是在周三晚到周四早开始的,导致时间不充足。
进而引发了根本原因:设计的时间压缩,进而导致大部分情况都是在“烂尾楼”上修补。
修补也只在本地做一些简单测试,不交作业,平白放弃一份免费测试。
修补过后,又没有充足的测试时间,匆匆交了作业。
此时,又不愿面对被狠狠hack的结局,互测积极性低。
死 亡 循 环。
事实上,即使我感到绝望的第三次垃圾,也只需要修改细节就能通过强测,是我无形中过于贬低了自己的成果。而这样的“逃避”,可耻且无用。
早些动笔,仔细阅读参考书,多想再写。解决方法,如是而已。