OO期末&第四单元总结
OO第四单元博客
提纲
- 总结本单元作业的架构设计
- 总结自己在四个单元中架构设计思维及OO方法理解的演进
- 总结自己在四个单元中测试理解与实践的演进
- 总结自己的课程收获
- 立足于自己的体会给课程提三个具体的改进建议
架构设计
类的设计
主要为一个操作接口类,及数个有关类图、状态图、顺序图的类,后者根据UmlElement的层次结构进行适当拆分。
-
Main
-
MyImplemetation 操作接口
- FindClassResult 对操作接口中需要寻找类的返回内容进行封装
-
MyClass 类图
- MyOperation 类图中的操作
-
MyStateMachine 状态图
-
MyInteration 顺序图
- MyLifeLine
内容的存储
关于类中内容的存储,主要有两个问题:
第一大问题是要实现ID, Name, Element三者之间的寻找,有时还要检测Name的重复性;其中ID和Element两两无重复,Name会有重复。本次作业主要通过两个HashMap实现,第一个HashMap关联的Key为ID,Value为Element;第二个HashMap的Key为Name,Value为ID。Name重复性检测在存储数据时完成,若当时第二个HashMap已有相应name的Key,则name重复。
第二个人问题是存储多种类型UmlElement时容器的设计问题。如果将所有类都单独设计两个HashMap则会过于繁琐,也无法实现需要查找跨不同类UmlElement的操作。对这个问题,我主要关注具体的需求,有需求的则单独构建两个HashMap,同时设立一个存储一切UmlElement的“顶层”HashMap。
四个单元架构设计的思维
第一单元
对表达式的解析、展开和化简,突出层次性。实现数据层次的抽象。
从Pre到第一单元,主要实现了从“别人设计类”到“自己设计类”的转变,对类的理解也从简单的”不同物体“深化到了程序设计时的抽象层次上。
但由于表达式中“递归下降”本身有一些面向过程的色彩,刚开始理解时出现了一些疑惑,写出了面向过程的代码。
第二单元
这个单元的架构设计上主要考虑三个方面:一是对电梯本身和电梯控制的区分,二是对需求的接收-处理时用到的生产者-消费者模式思想,三是对request进行适当封装。
难点在多线程的理解、及线程保护的处理上。认识多线程。我发现我在Sychronized-notify的设计上虽然实现了线程安全,但设计得比较杂碎,不利于别人在读代码时的理解。
第三单元
加入了Exception的处理和接口的实现。在类的设计上,实现已有的要求兼具适当封装。学习JML。
第四单元
理解UML。在实现已有的要求的基础上结合对内容层次结构的考虑。内容层次结构需要自己通过理解UML的存储存储结构去理解。与此同时,也学习了UML的数据存储结构。
阅读大量别人写的代码(官方包),接触package的应用。
测试理解与实践的演进
第一阶段-朴素认知:主要依靠课程网站上的评测机,及自己构造的简单样例,以之前的惯性思维“完成测试”,对测试并无深入理解;
第二阶段-依靠评测机的随机样例生成:发现以上方法不能保证完备性,经常会出现没有检测到的问题
第三阶段-评测机与主动构造样例相结合:理解老师讲的“在写程序之前提前想好测试样例”——主要针对边界条件等;同时使用评测机;接触单元测试。
课程收获
- 面向对象、架构设计的理解
- Java语法:得益于教材的精心设计,学习非常快,效率很高
- 提升编程能力:既是大代码量的训练,也涉及了之前学过的数据结构的知识
- git的使用:从0到熟悉
- 对测试的理解
- 时间安排上:课程的难点不仅在作业本身,更在时间安排上,如果错过了时间,即使有能力完成,也会失去分数
三个改进建议
- 第一单元的引导:表达式中“递归下降”本身有一些面向过程的色彩,刚开始理解时出现了一些疑惑,看到其他同学的博客也提到了这个问题,不知道课程组是否可以给予一些引导,减少同学学习过程中的弯路
- 增加应用讲解:学习UML、JML、Junit时并不非常清楚的了解以上技术在现今的工业界具体有哪些应用,有时网上的资料也非常少,建议可以增加这部分的讲解
- 统计作业完成用时:现在大家对OO用时的理解主要在一个字“长”上,但似乎并无准确认识。建议在收集作业时一并收集作业完成用时,并对同学展示,一方面有利于同学对自己能力的定位,另一方面也可以增强课程组对学生的了解、以及对每次作业情况的了解
OO第一单元总结补交
OO第一单元总结:初识面向对象
林世瀚 20185635 2022.3.6
1 程序分析
-
主要特点:
- 按照题目
形式化表述中的主要思路进行类和因子的构建:分为多项式、项、因子三大类,因子作为父类,被不同细分子类因子继承; - 针对自定义函数,采用“字符串替换”的思路处理;
- 未使用HashCode、HashMap等;
- 按照题目
-
重构历程:
- 在第二次作业进行重构,主要是进行不同类因子的拆分 和 针对重复使用字符串处理方法的封装(方便复用);
-
最终架构:(清晰及方便考虑,已省略set、get等方法)
-
分Class行数分析及每版的主要改动:
-
横向比较得出的不足:
- 架构设计的差距
- 方法实现的美观性
- 重复造轮子(主要是对已有的轮子不熟)
- 代码风格,主要是注释的清晰程度
2-3 Bug分析
2.1 公测和互测出现的Bug
第二次作业:公测得分67.9868分,3个点错误(以下三个问题)。
- 使用
Long解析BigInteger的创建,实际无法处理BigInteger;- 优化时将
sin(0)直接输出为0,没有考虑sin(0)**0=1;- 幂函数替换未外加括号;
第三次作业:公测得分61.1536分,4个点错误(3个点因问题1,1个点因问题2)。
- sum函数无法处理
BigInteger的情况;- 使用字符串替换函数时的逻辑小问题;
- 编写
cos代码时直接复制粘贴了sin的代码(toString)函数,导致cos(0)输出0(疏于检查,因此问题扣分多于其他Bug之和)。
本次作业中,互测被发现的Bug是强测的子集(可能与所在B/C房有关)。
2.2 出现Bug代码的特征分析
-
使用MatrixReloaded工具进行分析结果(如图)。从统计规律来看,复杂度较高的程序片段更容易出现Bug,减小方法复杂度、优化架构有利于减小Bug的出现可能;
-
自己写代码时,思路不够清晰的地方容易出Bug;
-
易出Bug的地方有以下特征(也是我互测中Hack他人的主要数据构造策略):
- 特殊值:特殊性主要在于程序中对其作出了特殊处理(尤其是优化时作出的处理,像
sin(x-x)这种),一旦特殊处理就容易出Bug; - 设计要求的“边界”:核心部分相对不容易有问题,一旦有问题也很容易发现;往往不容易被发现的是使用较少的边界部分。可以进一步地分为两类:
- 数据边界:如sum函数处理超出
long必须使用BigInteger的情况; - 操作边界:触发次数的特点是比较少在编写程序时容易对其理解模糊,需要特别关注才能搞清楚。如
i**+2等。
- 数据边界:如sum函数处理超出
- 特殊值:特殊性主要在于程序中对其作出了特殊处理(尤其是优化时作出的处理,像
3.1 发现Bug策略及启示
-
Hack他人:没有做评测机,构造数据的策略见2.2第3点。
-
启示:测试和Debug是程序设计中比较重要、又比较有难度的一个步骤。经过debug、hack他人的训(折)练(磨),老师在上课时讲解的比较科学的测试策略对我的吸引力显著增加。在总结出现Bug程序片段特征的基础上,争取在写程序时就想好对应的测试数据,多进行主动测试而非被动的改Bug。
4 架构设计体验
完成第一次作业时只是粗浅地只到对象、方法的概念,还不太理解面向的特征,在设计时思考好几种架构,也想到过一个非常简洁美观但完全面向过程的结构。最后还是根据指导书照葫芦画瓢的把程序简单分为多项式、项、因子三类,可以说让自己的程序大体具备了面向对象的特征,但在具体方法的设计、程序的细节上缺乏考虑,很多都不美观。
完成第二次作业时吸取第一次作业的经验和教训,对程序进行了完全的重写/重构。这是最费时费力的一周,虽然我的程序仍然称不上优雅,也使用了老师“并不推荐”的字符串替换方法,但仍然提供了我在第三周作业时不用进行重构的基础。
第三次作业在第二次作业的基础上添加了功能,但因为很快就通过了全部中测点,我没有进行认真地测试,最终出现了一些比较滑稽的低级错误。
总的来讲,这三次作业让我体会到了架构设计的重要性。一方面,分析自己的设计思路,在设计时只是大体的构建到了类的层面,具体方法的实现则是走一步看一步,我想这或许是出现一些错误的原因,也是之后还可以注意改进的点。另一方面,参考优秀的架构、阅读别人的程序确实受益很大,因此也要注意不能闭门造车。
5 心得体会
无论是作业还是理论课,总体感受都是挺充实的。不过希望自己能在时间节点的把控上更明智一些。

浙公网安备 33010602011771号