BUAA OO 第一单元总结

目录
  • OO 第一单元
    • 一、程序结构
      • 作业1
      • 作业2
      • 作业3
    • 二、Bug分析
    • 三、互测策略
    • 四、模式分析
    • 五、心得体会

OO 第一单元

三周的成长都在这里了

一、程序结构

作业1


作业1行数统计

  • 作业1只设计了两个类:Main和Polynomial. Polynomial中通过一个HashMap的属性来保存表达式,表达式的每一项的指数作为键,系数作为值。
  • 处理输入的方式是:先通过预处理去掉空格和连续的正负号,然后用相对简单的正则表达式获取每一项,解析出系数和指数,存到Map中。求导操作则是把每个Entry直接转换成字符串。
  • UML和复杂度分析图如下所示。
    BUAA OO 第一单元总结_第1张图片
    作业1UML图

BUAA OO 第一单元总结_第2张图片
作业1method

BUAA OO 第一单元总结_第3张图片
作业1class

  • 可以看出,绝大部分工作都是由Polynomial类中的static方法来完成,Main类只负责获取输入并调用Polynomial类。这实际上是一种非常面向过程的设计,在扩展性上留下了隐患。
  • 复杂度方面,主要是derive(求导)方法比较复杂,因为需要对项的特殊情况进行分支判断,我认为这是难以回避的。
    回到目录

作业2


作业2行数统计

  • 作业2基本上延续了作业1的设计,增加了WrongFormatException和Term类。Term中包含三个属性,分别表示一项中幂函数因子、正弦因子和余弦因子的指数。Polynomial中通过一个HashMap的属性来保存表达式。
  • 处理输入的方式是:构造项的正则表达式,用Matcher的find方法获取每一项,解析出系数和三种因子的指数,存到Map中。如果每次find到的字符串合并起来不是输入的整个字符串,则抛出异常。求导方面,考虑到两个不同项可能求导得到可以合并的项,所以具体的操作是对Map中的每一项求导,把结果加入到另一个HashMap中,最后输出这个Map.
  • UML和复杂度分析图如下所示。
    BUAA OO 第一单元总结_第4张图片
    作业2UML图

BUAA OO 第一单元总结_第5张图片
作业2method

BUAA OO 第一单元总结_第6张图片
作业2class

  • 可以看出,Polynomial类仍然承担了绝大部分工作。现在来看,把输入的字符串分解成项字符串,和把项字符串解析成Entry的工作可以拆分成单独的Parser类。
  • 复杂度方面,比较复杂的方法有三个:stringToTerms(把输入的字符串分解成项字符串), 涉及到Wrong Format的判断条件;addTerm(把项字符串解析成Entry), 涉及到几种因子的分支和循环;entryToString(把求导后的项转换为字符串),涉及到特殊情况的判断;我认为这几个方法相对复杂是比较正常的情况。
    回到目录

作业3

BUAA OO 第一单元总结_第7张图片
作业3行数统计

  • 作业3的关键点在于如何处理三角函数中对于因子的嵌套。因为嵌套因子的存在,这次作业的设计几乎与前两次完全不同。接口Factor包含derive和toString方法。表示五种因子的五个因子类继承自Factor:Expression, SinFactor, CosFactor, PowerFactor, ConstantFactor. Expression中主要的属性是Arraylist , 而Term中主要的属性是Arraylist , 模拟的是表达式的自然构成:一个表达式由若干项构成,而一个项由若干因子构成。
  • 处理输入的方式是:对于表达式字符串,首先把最外层的小括号替换成一对特殊字符,然后使用正则表达式非贪心匹配每个因子,根据因子的形式判断是加入当前Term还是加入新的Term。再由Term来判断具体生成哪种因子。求导方面,只需要实现Term和每种因子的求导规则和toString规则即可。
  • UML和复杂度分析图如下所示。
    BUAA OO 第一单元总结_第8张图片
    作业3UML图

BUAA OO 第一单元总结_第9张图片
作业3method复杂部分节选

BUAA OO 第一单元总结_第10张图片
作业3class

  • 这次作业是我比较满意的,因为比较恰当地运用了面向对象的设计思想,也感受到了它的优势。
  • 可以看出复杂度主要体现在SinFactor和CosFactor上,这是因为Term在把sin()或Cos()交给Sin/CosFactor的时候,完全不知道括号内部的情况,而Sin/CosFactor对于括号内部要求必须是因子,所以需要做一些判断。我认为我设计的判断算法还有优化的余地。此外,Sin/CosFactor内部的操作几乎是相同的,所以我认为可以增加一个三角函数类,来实现Sin/CosFactor的生成。这样做实际上是通过运用工厂模式来减少了冗余的代码。
    回到目录

二、Bug分析

  • 作业1、作业2未被测出Bug.
  • 作业3强测中有4组数据WA,互测中被攻击13次。出bug的地方是对于Sin/CosFactor括号内部是否WF的判断。这个错误非常值得我反思。因为我在提交前一小时(周六21点)发现了这一问题,开展了紧急修复的尝试,但最终没有成功,甚至引入了新的bug。仔细分析主要有三处值得改进的地方:一是对于自己程序的测试应该更早一些,留下更充裕的时间修复Bug;二是正如之前提到的,Sin/CosFactor判断WF的规则是相同的,在设计时应该合并,这样修改时会比较方便,我在尝试修复的过程中,需要先在SinFactor中修改,再粘贴到CosFactor中,浪费了一些时间,可以说一定程度上导致了修复的失败;三是在最后一次机会时不应该提交未经测试的最新版本,因为这样做承担了挂掉弱测的巨大风险。

三、互测策略

  • 互测采取了手动构造测试数据和自制评测机结合的策略。
  • 对于作业1,由于比较简单,针对边界情况手造数据效果更好。
  • 对于作业2和3,则主要依靠评测机找bug. 值得一提的是,尽管采取了一定的数据生成策略,想要依靠评测机抓到一些微小的bug还是需要跑足够多的数据,例如作业2一位同学的程序,在1500组测试数据中仅有1组报出了错误。

四、模式分析

  • 从全局上来看,作业3与前两次作业相比改动是比较大的,主要体现在作业3把每一种因子都设计成了一个类。但我认为这并不说明前两次作业的设计不好。前两次作业主要是在可扩展性和性能上作出了取舍。即便是在已知作业3要求的情况下进行设计,我想我的前两次作业还是会保留用键值对存取项的做法,因为在因子的情况比较简单时,这样做更利于优化,出错的可能性也更低。
  • 针对作业3,我想谈一谈工厂模式。我在提交的作业中完全没有用到工厂模式,而正如我在第一部分程序结构分析中提到的,对于Sin/CosFactor几乎相同的生成方式来说,应该提取成为一个工厂。但是,对于所有的五种Factor来说,我认为不需要一个总的工厂,这主要是因为它们之间的相似度不高,把生成的方法封装到各个类的构造方法中反而使结构更清晰。这实际上仍然体现了可扩展性和性能上的取舍。

五、心得体会

  • 整体来说非常有收获,面向对象的设计思想很妙。
  • 设计模式非常关键,还需要多多学习。
  • 时间管理有待加强。我的时间线大致是周一互测;周二OS;周三早课+上午满课,下午会OO一小会但整体比较摸,晚上高强度的上机/讨论课结束后又没什么精力OO了;所以OO工作基本上是从周四才正式开始,时间比较紧迫。解决方法是周日必须完成互测(即使未完成周一也不做了);周一OS,周二晚上拿到题就立刻开始思考,这样即使周三下午状态不好,由于已经有一定思路了,效率会更高。
  • 三次作业都几乎没有优化性能,主要是因为时间不够和懒,没有充分利用作业的训练机会,以后应该改进。
  • 三次作业代码零注释,由于作业规模较小,且完成时间比较集中,没有引发什么问题,但是以后的作业中应该添加恰当的注释。

你可能感兴趣的:(BUAA OO 第一单元总结)