BUAA面向对象设计与构造——第一单元总结
BUAA面向对象设计与构造——第一单元总结
第一阶段:只支持一元多项式的表达式求导
1. 程序结构
由于是第一次接触面向对象的编程,加之题目要求不算复杂,我在第一次作业中并没有很好利用面向对象的特点,只建了两个类。
第一个DerivativeFunc类只包含main函数,而剩余所有功能包括正确性检查、求导和输出都全在类Poly里。这两个类之间也没有继承等关系,所以整体看起来还是偏向C语言的思路,这也是这次作业最大的问题。在类Poly里面,我建立了两个链表来分别存储每一项的系数和幂指数。
从以上两个复杂度统计可以看出,因为第一次作业只有两个类,因此大部分的操作都集中在在OutputPoly这个输出函数中。这也导致了它的复杂度偏高。
2. 特殊处理
关于输出字符串的正确性检查,我使用了正则表达式的匹配。题目中给了关于大数处理的提示,因此我选择了使用java自带的BigInteger类型来处理系数和指数。
3. 存在的bug
第一次作业没有考虑正则表达式爆栈的情况,确实是考虑不够全面。后来看到评论区提供的独占模式,我就在后两次作业中都改掉了。在强测中虽然通过了全部的正确性检查,但是性能分没有拿到满分。原因在于我的优化部分少优化了一种情况:对于首项为负数系数,而之后的项中有正数系数的表达式,可以先输出正数系数的项,以减少一个‘+’的长度。
第二阶段:支持一元幂函数与三角函数乘法和加法的表达式求导
1. 程序结构
在上次作业中,我的整个表达式都存储在一个类里,没有进行划分。而这次由于加减法相连的项的格式不统一,所以我将表达式分割为了多个项,为每一个项实例化了一个Term类。
2. 特殊处理
一开始我的设想是为表达式、项和因子都分别建一个类,因子相乘得到项,项相加得到表达式,上层类使用链表存储下层类的实例化对象。但是后来我发现在这次作业中,每个项的形式都能用a*x^b*sin(x)^c*cos(x)^d来表示,因此无需建立因子类(当然这个时候不建第三次作业也得建)。
我在Expression类中建立了以Term类为键值的Hashmap,而value部分则存储这一项的常数因子。
private HashMap<Term, BigInteger> hashExp = new HashMap<>();
由于Hashmap可以通过键值直接查找结点,因此这样的存储方式可以方便同类项的合并。为了实现这一功能,需要在Term类里重写equals()和hashCode()函数。每个项由numDegree, xDegree, sinDegree, cosDegree四个参数来确定,只要后三个指数参数相同了,那么就可以判定两项是同类项,再将系数相加,就可以实现同类项合并。
对于优化部分,我只实现了cos2x + sin2x = 1, 1 - cos2x = sin2x , 1 - sin2x = cos2x 三种形式的优化。由于无脑优化上述三种情况可能会使得输出长度反而增加,因此我只使用二重循环遍历了hashMap,将确定会减少长度的情况进行了优化。包括系数相等的情况,以及系数不相等但优化后可以合并同类项这两大类。我这次所做的优化是不完备的,我只能保证我优化的情况一定可以减少长度,但是所有能减少长度的情况我并没有涵盖完全。例如(cos2x + sin2x)2 = 1这种整体再平方的优化我就无法识别了。
3. 存在的bug
这次强测中错了一个点,线下检查的时候发现是优化导致的错误。在Term类的replaceTerm()方法中,当系数不相等时应该剩余系数大的项,而我使用了系数小的项的幂指数来进行sinx的指数-2的修改,导致了错误。这主要还是因为我线下自己测试的数据不够完善。
第三阶段:支持一元幂函数与三角函数乘法、加法及嵌套的表达式求导
1. 程序结构
这一次作业由于出现了嵌套规则,使得整个表达式必须分割成不同的因子,分别求导再组合。因此我设置了表达式类、项类和一系列因子类。这些同等级别的因子类同时实现一个DifferPrinciple接口。通过这个接口可以在Term类里统一管理不同类的因子,使得他们可以在同一个链表里存在。每个因子内部有求导函数differ()和原字符串返回函数getOriginStr(),像sin和cos两个类的求导函数,还会递归调用各种因子类的求导函数。通过调用每个因子的这两个函数,可以在Term里实现因子相乘的求导。最后在Expression类调用Term类的求导结果并相加。
从上面的统计中可以看到主类MainDiffer中有三个方法复杂度很多,这一点在下一节“特殊处理”中详述。除此之外的类由于划分比较细,因此复杂度都比较低,实现了高内聚低耦合。
2. 特殊处理
这次作业由于出现了三角函数的嵌套嵌套形式,因此如果用“sin\\(.+\\)”来匹配sin因子,会导致sin(x)+cos(x)被识别为一个因子。因此我没有使用正则表达式直接匹配,而是使用了类似于编译原理中递归下降分析法的形式,通过三个分别检查表达式、项、因子的方法相互调用来分割表达式并检查正确性的。这也就导致了这三个表达式的复杂度较高。这里有一个值得改进的地方在于,我第一遍扫描输入字符串时只检查了正确性,然后去掉全部空格,再传入Expression类进行第二遍扫描并分割实例化其他类。这样两次扫描比较多余,应该在第一次扫描时同时进行分割操作。当初只是为了贪图去掉全部空格这个操作,才导致代码架构的冗余。
对于表达式因子这个特殊的因子,我还是建了一个类,在这个类内部先对括号进行识别并且去掉多余的括号,再实例化Expression类。这样结构更清晰,也避免了在三角函数因子类直接实例化Expression类导致的括号匹配错误等问题。
由于这次性能分只占了5分,因此我没有做过多的优化。只是针对系数为±1,幂指数为1,多层括号等简单优化。
3. 存在的bug
强测中还是错了一个点,经过排查是因为表达式因子去除多层括号的时候不够严谨,去掉了不该去的。在ExpFactor类differ()函数中,我判断了如果内层嵌套函数是由一对括号括起来的,那么求导后输出也不需要加括号。但是我忽略了例如(x+x)*sin(x)+cos(x)这种表达式形式,也会被识别为前后由括号括起来。因此会导致我求导后的输出少括号,结果也就不可能正确了。
4. 测试策略
由于我们没有互测,以下的测试策略只是针对我个人程序调试。对于正确样例,我是先列一张表,横向和纵向都是各类因子,然后每个交叉点都要覆盖这两种因子的相加、相乘和嵌套(不符合规则的则去掉),然后手工写一系列的测试代码。错误样例包括在各种地方出现的空格、括号不匹配、非法字符和不完整表达式等。不过在我写这篇博客之前,我浏览了一些别人的博客,发现很多人是另写一个程序或者脚本来自动生成大量测试样例,瞬间觉得自己手工写测试代码太低级了。这一点也是下一单元很需要改进的地方。
总结
1.重构模式
后两次作业我都是完全重构写的,主要是因为前一次写的时候没怎么考虑功能的扩展,即使第二次稍微考虑了也没想到嵌套规则的复杂度。这虽然在第一单元里没有太费时间,但是我觉得在之后更高难度的题目中,如果我每次都重构可能时间和精力都要浪费很多。因此第二单元开始尤其是第一次作业,最好就考虑全面一些,而不是只为了实现这一次作业的要求。目前为止我的程序结构更贴近于工厂模式,通过实例化同一接口下的不同类来完成要求。
2.感想与收获
这是我第一次完整的用面向对象的思想来编程,所以一开始还不太适应,总是想写很多个方法来互相调用。到了第三次作业稍微有些进步,将输入分割成很多个不同的类,每个类自己求导,而更高一层次的类再实例化不同的类来组合。由于16级没有互测部分,因此我对自己程序的bug发现与调试还不够完善,测试程序的完备性也有待提高,这些都是未来需要解决的问题。总之有很大收获,也有更多需要改进之处。
BUAA面向对象设计与构造——第一单元总结的更多相关文章
- BUAA面向对象设计与构造——第二单元总结
BUAA面向对象设计与构造——第二单元总结 第一阶段:单部傻瓜电梯的调度 第二阶段:单部可捎带电梯的调度 (由于我第一次写的作业就是可捎带模式,第二次只是增加了负数楼层,修改了一部分参数,因此一起总结 ...
- 从结构和数字看OO——面向对象设计与构造第一章总结
不知不觉中,我已经接触OO五周了,顺利地完成了第一章节的学习,回顾三次编程作业,惊喜于自身在设计思路和编程习惯已有了一定的改变,下面我将从度量分析.自身Bug.互测和设计模式四个方向对自己第一章的学习 ...
- 面向对象设计与构造:JML规格单元作业总结
面向对象设计与构造:JML规格单元作业总结 第一部分:JML语言理论基础 JML语言是什么:对Java程序进行规格化设计的一种表示语言 使用JML语言有什么好处: 用逻辑严格的规格取代自然语言,照顾马 ...
- 面向对象设计与构造:oo课程总结
面向对象设计与构造:OO课程总结 第一部分:UML单元架构设计 第一次作业 UML图 MyUmlInteraction类实现接口方法,ClassUnit和InterfaceUnit管理UML图中的类和 ...
- 暑期java(面向对象设计)学习第一阶段总结
0.前言 本次博客针对的是暑假学习java(面向对象设计)的前三次作业的小结,第一次作业:7-1 对三个整数排序 7-2 对四个整数排序 7-3 对十个整数进行排序 7-4 对多个整数进行排序 第二次 ...
- OO第一次博客作业--第一单元总结
OO第一单元总结 面向对象设计与构造的第一单元,对“面向对象”的概念还根本不理解不熟悉,只觉得需要“分模块”,但不知道怎么分,分多少模块,怎么根据需要的模块的功能建立类.学习的进度又太慢,根本跟不上出 ...
- BUAA OO 2019 第一单元作业总结
目录 总 架构 Controller Model 输入处理 代码静态分析 行数 方法复杂度 UML 类图 优点 缺点 坑 输入 非法的空白字符 输入的简并处理 运算 浅拷贝 可变类型与不可变类型 ...
- 2020-BUAA-OO-面向对象设计与构造-第四单元总结&课程总结
咱的OO结束辣! Part1: Unit4 Summary 本单元作业,我主要使用了适配器模式和访问者模式.总体上看,代码量和文件数量有所上升,但配合分包等措施后,文件结构清晰,各部分耦合度均较低.缺 ...
- OO面向对象第一单元总结
OO面向对象第一单元总结(表达式求导) 写在前面: 魔鬼课程oo第一单元终于结束,当终究要落笔总结,竟不知从何写起…… 回首再去看第一次的作业,你会满足于那时的幸福,或许,这就是成长吧! 千言万语,一 ...
随机推荐
- ActiveMQ 的安装与使用(单节点)
环境:CentOS6.6.JDK8 1.下载:http://archive.apache.org/dist/activemq/5.11.1/apache-activemq-5.11.1-bin.tar ...
- Oracle DB Day02(SQL)
--数据库下表一般都是从1开始,例如字符串等 SELECT *FROM employees --字符串连接CONCAT() ,CONCAT(CONCAT(EMPLOYEE_ID,','),SALARY ...
- 如何参与flink开源项目
参与flink开源项目 https://flink.apache.org/how-to-contribute.html 1.回答社区问题 2.撰写bug报告 3.对于改进建议或新的特征 4.帮助别人并 ...
- django --视图装饰器
- 推送提交(git push)
当需要同别人共享某个分支上的工作成果时,就要把它推送到一个具有写权限的远程仓库.你的本地分支并不会自动同步到远程仓库,必须要显式地推送那些你想要与别人共享的分支.这样一来,你可以使用私有分支做一些不想 ...
- Luogu P1082 同余方程(NOIP 2012) 题解报告
题目传送门 [题目大意] 求关于x的同余方程 ax≡1(mod b)的最小整数解. [思路分析] 由同余方程的有关知识可得,ax≡1(mod b)可以化为ax+by=1,此方程有解当且仅当gcd(a, ...
- TextView设置不同字段不同点击事件
转载自:http://www.apkbus.com/blog-160625-59265.html package com.example.fortextdemo; import java.util ...
- 你循环的时候就可以给他们赋值了,那么就不用addClass,再根据类选择器处理,代码能一气呵成就别写成两段了
function onCopyButtonClick() { $(".index:checked").each(function () { $(] + "__WeekCo ...
- Jquery笔记和ajax笔记
Jquery笔记:jQuery是一个JavaScript函数库,专为事件处理设计 1.jQuery的引入 <script text="type/javascript" src ...
- Object类中方法详解
目录 概述 hashCode方法 getClass方法 toString方法 equals方法 clone方法 finalize方法 概述 Object 是类层次结构的根类.每个类都使用 Object ...