“OOP永远是我的好朋友爸爸!”        ——来自某无能狂怒的菜鸡

  身处在OO的第一个摸鱼黄金周中的我,感觉到了巨大的满足感。如果写博客这种充满意义的事情可以代替我们亲爱的作业,那么我提议每周来两个:)下面开始正经分析~

Homework 1  简单多项式求导

  • Part1 程序架构分析

  面对人生的第一次面向对象程序,没有学过java的我认认真真思考了整个代码框架,最后通过不懈努力,完完全全写成了面向过程(毕竟我又没得对象)。

  在这次作业中使用了三个类:PolyDerivation、Poly、Term。程序入口(main)、输入、格式检测都被我堆砌到了PolyDerivation的类中,导致PolyDerivation的功能不明确,但是有着大量的方法。当然值得一提的是,我采用了预处理的手段简化了很多判断问题,也有效的避免了大正则爆栈。Poly是多项式类,主要用了指导书中的HashMap数据类型保存了每一个单项,并切割将每一个项放进Term类。Term类包含了degree和coeff两个成员。可能这个切割Poly是我唯一的面向对象吧。(逃

  本次作业的求导本身只是简单的大数相乘,问题不大。但是由于我不知道重写toString方法,导致写了80行的大条件语句实现了output。又由于checkstyle问题被迫拆成了两个方法。这真的有种造轮子的感觉!

  本次作业的类图和复杂度如下。

  

  

  从这个类图中,不难看出我采用的是直线式编程呢个,一条路走到底。好处在于简单好写不易出错(当然是针对我这种菜鸡而言),坏处是各个类不够简单,耦合度有点高,面向数据可拓展性基本为0。

  • Part2 程序bug分析

  由于我的面向过程程序写的很好:),本次强测和互测均未被发现bug。其实还是第一次作业要考虑的情况比较线性,使用这种面向过程思维,只要处理周到,还是不会出很多问题。

  • Part3 发现别人的bug

  在OO为我们提供的狼人杀游戏中,我充分认识到了狼人的可怕之处。夜半惊魂,起身刀人。

  第一次作业的bug基本上都集中在鲁棒性测试上,也就是利用他们漏判\v,\f等空白字符,找到了很多bug。另外就是StackOverflow问题。但是没有找到太多功能性bug。

Homework 2 带三角函数的简单表达式求导

  • Part1 程序架构分析

  第二次作业增加了三角函数。虽然我们都猜到第三次作业可能就是嵌套求导。但是懒惰战胜了理智,我还是没有选择重构代码。我选择了一种错误率最低,优化的可操作性最高的三角函数通式法。也就是把所有的项都表示为(a,b,c,d) 的四元组形式。用ArrayList的数据结构存储项(其实是不会HashMap的重写equals方法)。

  由于没有选择重构,本次代码还是三个类,也就是在第一次作业的基础上,修改了derive方法,求导也只是(a,b,c,d)的数字转化。反思一下,这其实是面向数据编程,是不太可取的。事实上,我也为第三次作业付出了代价。个人认为最好的方法其实是讨论区大佬所说的写两个版本进行对拍,一个版本为了这次优化,另一个版本为第三次做准备。可惜我太菜了,也确实没有这么多精力。

  优化方面,由于能力有限,我只做了一些简单的sin(x)^2+cos(x)^2和合并同类项的优化。

    

    (死亡复杂度预警)高复杂度来源于poly中大量的条件输出和优化方法。

    

这一次作业几乎和第一次一样,只是把幂函数的两元变成了四元,缺点还是耦合度高,几乎没有可拓展性。

  • Part2 程序bug分析

  第二次的强测没有发现bug,但在互测中被发现了负指数幂的bug,因为在程序中自己手抖把去除第一个负号写成了replaceAll(“-”,“”)。。。导致了整个项中的负指数都被我去掉了。这只能说明我的本地测试没有过关,像这种比较好发现的bug却没有发现。bug修改也很方便,直接String.substring方法处理完事。

  在这周我也见识到了自动测试的无比威力,通过随机化测试,应该可以避免绝大多数类似我这种功能性bug。这也是今后自己需要补充注意的。

  • Part3 发现别人的bug

  经历了第一次作业的狼人杀,我发现大家针对恶意输入鲁棒性测试的处理能力大大提高了,具体表现为用鲁棒测试很难测出bug(魔鬼)。但是我仍然构造了含大量空格和\t的测试样例并成功找出了bug。即sin(x)  *     cos(x)       *     +      1         这样的数据。

  另外一个大面积出错的点在于缺项数据的处理,如sin(x)*、cos(x)+(然鹅我自己居然在第三次作业里挂了这个点,哭了)

Homework 3 终极无敌嵌套表达式求导

  • Part1 程序架构分析

  老实说,虽然在之前已经猜到了嵌套求导,但是看到这个指导书的那一眼,我内心是拒绝的。我完全没有想到接下来的两天我能完成这个project。(并且还要学习OS)然而狗急跳墙,人急了原来也是能写出OO的,虽然写的很烂。

  第三次作业宣告了我前两次作业结构的完全颠覆。也就是说再也没有所谓的通项式求导,唯一剩下的只有基础求导规则和因子求导。我苦思冥想着作业架构,咋也想不到,于是就出去看了场电影激发灵感。

  困扰菜鸡的第一个问题就是怎样进行格式检查。由于我在前两次作业中都是采用了预处理+大正则的手段,而这一次这种递归检查用大正则我确实是做不到的。那么第二个大问题就是求导。而格式检查和求导本质上其实都是递归的过程。所以在本次作业采用了递归下降的思路,将一个多项式按照加法分割(利用堆栈进行括号检查),分割成项之后送入项类。项按照乘法分割,分割成因子之后送入因子类。因子包括四类基础类型:Num、x^a、[sin][cos](x)^a、(表达式)。其中表达式又被送入表达式类,形成了一种递归的流程。表达式、项、因子这些类中都包含了各自的分割split()、格式检查check()、求导deri()的方法(后来想想我是不是应该建立接口抽象方法???)这是笔者自认为三次作业中最面向对象的一次,也许这就是潜移默化被逼出来的进步吧。但是这次课传授的继承和接口我没有灵活运用进去。对于继承和接口只是模糊地有一定概念,但是完全不会用。

    

    类一多起来,死亡复杂度果然直线下降。

    

  稍微面向对象一点的作业,Factor和Item类由于存在大量循环和判断,复杂度还是很高。我认为如果将Factor再细分成xFactor、sinFactor、cosFactor、expFactor也许会大大降低复杂度,也能增加可拓展性。

  • Part2 程序bug分析

  本次强测挂了一个点,就缺项输出WF。这里我就要谈一谈split的一个坑点,split会自动丢弃末尾空值(????)。强测的最后一个点2 * (sin(x)) *(x)*sin((x))^+1*x*cos(x)^+2*cos(x)*(((x)))*-1*,也就是缺项检测,末尾空值被自动丢弃,甚至都没有判断空串的机会。。。于是就这么心安理得地挂了。

  互测中由于被禁止了WF输入,我这个bug没有被hack。而又因为这次我完全没有优化!!!所以输出数据稳得很,功能性bug也没有被发现bug,所以是0hacked。

  • Part3 发现别人的bug

  第三次的互测禁止了WF输入,也就是说鲁棒性bug完全被杜绝了(其实还可以让别人的程序误判WF),只剩下了功能性bug。本以为互测屋bug数会大量减少的我,经过测试发现功能性bug也不少。功能性bug主要有两类:一类是优化过程中出错、一类是递归下降处理不当。

  具体来说,优化出错通过大量随机测试其实不难发现,而sin(((((((((((((((((((((((((((x)))))))))))))))))))))))))))的式子可以检测是否TLE,另外我们room中还有同学漏判了\t和^+的情况,也是很不幸成为了大礼包。

  • Part4 第三次作业的反思

  由于第三次作业很难,所以part4是我对第三次作业的一些反思。可以看到的是,在第三次作业中,我没有再把诸如输入处理和格式判断塞到Main中去,而是分成了Input类;也没有再一遍遍手写WRONG FORMAT!而是写了一个Error类,可能这也是一些微不足道的面向对象吧。本来是应该再写一个Output类进行优化和toString()的,然而这次作业的优化已经超出了我的能力范围,所以就此放弃,把输出工作也直接交了各自抽象层次。

  具体来看,我把整个多项式的处理抽象成了四层对象(即使我还是不能很好地理解形而上的抽象),四个对象之间的关系处理是让我很头疼的一部分。因为Exp,Item,Factor,Num并不是简单的包含关系,他们其实是PPT最后一页的那种彼此纠葛相爱相杀的关系,然而当时的我是菜的看不懂的:)。这种层次化设计我认为是需要细细体会的。我在这次作业中完全没有用到继承和接口,就是因为我几乎没有对面向对象的这种“获取数据处理的归一化能力”的思想产生概念。换句话来说,即使第三次作业我的确对表达式、项做了一定的封装,然而我的程序本质上还是面向过程的。。。。不说了,我去看大佬的代码和thinking in java恶补了。

创造模式思考和代码重构

  代码重构只针对第三次作业。(第三次其实也包含了第一二次)

  重构思路:数据层面抽象管理使用继承,非数据使用接口或继承。重点参考PPT实现。

  创造一个Factor父类,子类xFactor、sinFactor、cosFactor、expFactor。创造一个comFactor父类,子类add、multi。multi规则产生原来代码中的Item,add产生exp。值得注意是递归过程,也就是expFactor会被送回到add规则中。add和multi通过给自的分割符对整个加法项和乘法项进行拆分送回Factor。

  此外定义接口deri和check,每一个Factor有其对应的求导规则和格式检查规则。Input和Output分别用于输入预处理和优化输出。

  这样的代码结构应该会大大降低代码的耦合度,也会更具有面向对象的抽象思维。

  至于创造模式(Creational Pattern),本菜鸡还确实是在上一周的OO课上才知道的名词。现在只能说不明觉厉,比继承和接口又上了一个抽象等级:)学习了 一下之后,感觉可以通过使用抽象工厂(Abstract Factor)进一步增强代码的可拓展性。具体就是建一个Factor工厂,把基础因子xFactor、sinFactor、cosFactor、expFactor都塞给工厂。由工厂类统一管理创建和调用过程,这样封装得也就更加彻底,今后新建因子类只需要修改Factor。建造者模式(Build Pattern)好像完全不会用,应该是用来调度整体对象(???)。不知道自己理解的对不对,希望大佬指教。

想说的话。。。

  三次OO作业不仅让我快速学会了java语法,也领悟到了面向WF鲁棒性的重要性。这是我第一次运用工程化思想,以前的题大多都是给出固定的input->利用一些算法和数据结构得到结果->进行输出。而这也是典型的面向过程编程。作为一个码代码能力低下的菜鸡,要在短时间内顺利完成从面向过程到面向对象的过渡,并写出动辄几百行的代码,其实是很吃力的。所以三次作业三周,我也几乎花费了大量的时间在OO上(救救孩子的OS)。我也确实感觉到了自己的进步,尽管可能还不够多。所以说,OO界面的毒鸡汤也还有几分道理??不经巨大的困难,不会有伟大的事业:)

  自勉自勉~

菜鸡谈OO 第一单元总结的更多相关文章

  1. 菜鸡谈OO 第二单元总结

    “欢迎来到(玄学)多线程的新世界” Homework1 单部傻瓜电梯调度 Part1 多线程设计策略 第一次学到了线程这个概念,与之前的编程体验大有不同.最大的区别在于从原本的线性发生程序变成了多个行 ...

  2. OO第一单元总结

    OO第一单元作业总结 一.前言 开学四周,不知不觉已经做了三次OO作业.事实上,每一次作业对我来说都是很大的挑战,需要花费大量的时间和精力来学习. 虽然学得很艰苦,但最后还是连滚带爬地完成了.(好惨一 ...

  3. OO第一单元优化博客

    OO第一单元优化博客 第一次作业: 合并同类项+提正系数项+优化系数指数0/1=满分 第二次作业: 初始想法 一开始是想以\(sin(x)​\)和\(cos(x)​\)的指数作为坐标,在图上画出来就可 ...

  4. OO第一单元(求导)单元总结

    OO第一单元(求导)单元总结 这是我们oo课程的第一个单元,也是意在让我们接触了解掌握oo思想的一个单元,这个单元的作业以求导为主题,从一开始的加减多项式求导再到最后的嵌套多项式求导,难度逐渐提高,编 ...

  5. OO第一单元总结-多项式求导

    OO第一单元总结-多项式求导 一.第一.第二次作业总结 因为前两次作业设计复杂度差别不大,因而放在这里统一总结. 基于度量分析程序结构: 前两次作业确实存在缺乏可拓展设计的构想,基本还是面向过程的思维 ...

  6. OO第一单元作业总结

    oo第一单元的作业是对多项式的求导.下面就是对三次作业分别进行分析. 第一次作业 分析 第一次作业相对来讲比较简单,甚至不用面向对象的思想都能十分轻松的完成(实际上自己就没有使用),包含的内容只有常数 ...

  7. 【OO学习】OO第一单元作业总结

    OO第一单元作业总结 在第一单元作业中,我们只做了一件事情:求导,对多项式求导,对带三角函数的表达式求导,对有括号嵌套的表达式求导.作业难度依次递增,让我们熟悉面向对象编程方法,开始从面向过程向面向对 ...

  8. 【作业1.0】OO第一单元作业总结

    OO第一单元作业已全部完成,为了使这一单元的作业能够收获更多一点,我回忆起我曾经在计算机组成课设中,经常我们会写一些实验报告,经常以此对实验内容反思总结.在我们开始下一单元的作业之前,我在此对OO第一 ...

  9. OO第一单元(前四周)作业总结

    OO第一单元(前四周)作业总结 OO第一单元(前四周)作业总结要求(第四次作业) 0.前言 本次博客针对的是本人学习Java的第一阶段的三次作业的作业总结 第一次作业的内容是:7-1 计算税率 (20 ...

随机推荐

  1. 关于shell变量的继承总结

    结论: 默认,父shell和子shell的变量是隔离的. sh方式运行脚本,会重新开启一个子shell,无法继承父进程的普通变量,能继承父进程export的全局变量. source或者. 方式运行脚本 ...

  2. A previous installation of Qt5 Visual Studio Add-in was detected. Please uninstall it before running this installer解决办法

    前段时间在安装Qt Visual Studio插件的时候,安装到一半不小心中止了,结果后来怎么安装都不行,提示已经安装了,要先卸载, 可是到哪里都找不到有卸载的,因为压根就没有安装完成.这可害苦我了. ...

  3. 【easy】108. Convert Sorted Array to Binary Search Tree

    Given an array where elements are sorted in ascending order, convert it to a height balanced BST. Fo ...

  4. CentOS 安装 Docker

    前言:其实安装步骤Docker官网很详细,如果有些人英文不好看的比较慢的话就可以直接看我的,我也是摘自官网,具体步骤如下 1. 安装依赖包 $ sudo yum install -y yum-util ...

  5. IDEA内的SpringBoot插件安装与SpringBoot项目生成地址

    最新安装idea,在新建项目时没有spring initializr选项,也没有spring assistant选项.因此需要安装相应插件 在菜单栏 file>>settings>& ...

  6. spring5.0.2.RELEASE源码环境构建

    Spring5 源码下载注意事项 首先你的JDK 需要升级到1.8 以上.Spring3.0 开始,Spring 源码采用github 托管,不再提供官网下载链接.大家可自行去github 网站下载, ...

  7. 关于Integer比较问题

    public class Test { public static void main(String[] args) { Integer a=127; Integer b=127; System.ou ...

  8. insert into

    1. INSERT INTO t1(field1,field2) VALUE(v001,v002);            // 明确只插入一条Value 2. INSERT INTO t1(fiel ...

  9. 2018-2019-2 网络对抗技术 20165328 Exp2 后门原理与实践

    实验内容: 任务一:使用netcat获取主机操作Shell,cron启动任务二:使用socat获取主机操作Shell, 任务计划启动任务三:使用MSF meterpreter(或其他软件)生成可执行文 ...

  10. 时分秒计时器 js

    <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...