本单元作业总结
第一次作业
本单元的第一次作业主要是UML类图的解析和相关的查询操作。
在第一次作业中,因为只有类图的元素,所以我选择了将UML类图按照元素中的父子关系建立成了UML类图树,以类为根,然后将所有parent为该类的元素作为类的儿子,然后依次类推进行构造,这样就能方便的找到属于某个类的方法、属性、关联对端等等,UML类图的结构为类(或接口)在最顶层,下一层是属性、方法、关联、泛化和实现,在方法下面还有参数,关联下有关联对端。
其中为了编程方便,我选择为每个类或接口都设置三个列表,第一个列表存储这个类或接口继承的类或接口,第二个列表存储这个类或接口下关联的类或接口,第三个列表存储这个类直接实现的接口
值得一提的是,第二个列表的初始化是通过UMLassociate间接完成的,只有属于UMLassociate的两个对端都已经出现之后才分别把两个类或接口加入对方类或接口相应的列表。
完成了类图的解析之后,第一次作业主要实现了以下几个方法,首先是查询图中类的个数,只需要查询有多少颗树即可。第二个方法是查询类中的操作有多少个,只需要先找到类对应的树,然后看这个点下辖的儿子中有多少个是操作即可。第三个方法是类中的属性有多少个,和第二个方法类似。第四个方法是有多少个关联,由于之前解析的时候已经出师好了关联的类或接口,所以只需要查询类对应列表的大小即可。第五、六个方法分别是查询类操作的可操作性、属性的可操作性,只需要查询类下儿子有没有名字相同的,如果有相同的记录可见性即可。第七个方法是查询类的顶级父类,此处就需要初始化的第一个列表,只要类对应的列表不为空,就可以找到更高的父类,直到此列表为空,此时的类就是顶级父类。第八个方法是查询类实现的全部接口,此处是此次作业的难点,首先需要记录所有该类直接实现的接口,对于所有直接实现的接口,查询这些接口继承的接口并记录,然后还需要查询父类实现的接口并记录。用类似宽搜的办法就可以实现,需要注意的是由于接口可以出现重复继承,所以在搜索的时候需要记录是否曾经搜索过,如果搜索过就不必重复搜索。第九个方法是查询类是否违背信息隐藏原则,只需要看类下儿子作为属性的是否有非private,有记录即可。
我在本次作业中出现了一个bug,就是没有在搜索实现接口时没有记录是否曾经搜索过,因此ctle了一个点,这提醒我们要注意程序的时间复杂度分析。
第二次作业
本单元的第二次作业在第一次作业的基础上增加了对UML状态图和顺序图的分析。
因为UML状态图的顺序图的天然结构,我模仿上次作业构建了UML状态图树和UML顺序图树。因为在UML状态图的查询方法中只会涉及到UMLstatemachine,UMLTransition和各类UML的状态,所以我在解析的时候只解析了这些元素。将状态机作为树的根,下面是状态和转移。为了方便编程,我对每一个状态初始化了一个会转移到的状态列表。同时在顺序图的方法中会涉及到的只有UMLinteraction,UMLmessage和UMLlifeline,其中interaction作为树根,下面是message和lifeline,message有两端,分别是两个lifeline,为了编程方便,需要设置一个列表记录lifeline的另一个来源是什么。
关于新增的六个方法,实现和类图的方法实现类似,关于数目的只需要查询根或儿子符合条件的个数,关于后续状态查询和incoming消息查询则使用初始化的两个列表即可。
我在本次作业的强测中获得了100分。
第三次作业
本单元的第三次作业在第二次作业的基础上增加了对UML图的合法性判断。
我认为本次作业的主要难点是理解R001和R002-R004的实现。
R001说针对类图中的类(UMLClass),其成员属性(UMLAttribute)和关联对端所连接的UMLAssociationEnd 均不能有重名。所谓的关联对端所连接的UMLAssociationEnd是指一个关联中,不是本类的另一个end的名字。
R002是不可以有循环继承,此时从一个类或接口开始搜索,每次搜索自己继承的类或接口,然后看看能不能搜回自己即可。如果能搜回自己就说明有循环继承。
R003是不可以有重复继承,注意到类如果不是循环继承的话就不可能出现重复继承,所以在这里只查询接口即可。这里也可以用一个搜索解决,把所有搜索过的接口都做上标记,如果出现了搜到有标记的接口的情况,那么就是出现了重复继承。
R004是不可以重复实现同一个接口,这个可以直接借用UML类图中的查询实现接口的方法,在查询的时候检查当前的接口是否已经记录过,如果有记录过的话就出现了重复实现。
其他的检查只需要进行简单的计数即可。
我在本次作业中出现了一个bug,原因是对R001的理解出现了问题。
架构设计以及OO方法理解的演进
第一单元
第一单元是各类求导问题的结合,在这一单元我在不停的重构,这让我意识到我对OO的所谓“面向对象”的理解有很大的不足,在最后一次作业中才能做到把所有元素完全分离,为每个元素,也就是所谓的对象,编写与其相关的方法。在这一单元中,我学习到了架构设计的方法,为了保证一个架构的可扩展性,一定要尽可能的解耦,并且在写代码之前就整理好代码的架构,不然就容易出现方法归属不明的状况。
第二单元
第二单元主要是多线程编程问题,在这一单元,我对架构的设计的理解更进了一步,因为在这一单元中我们学习了很多程序的设计模式,包括生产者消费者模式,观察者模式等等,这让我对每一个对象职责的理解更进一步,同时理解了一些架构设计的套路。
除此以外,因为这单元是多线程编程问题,我还学习到了安全编程的概念,需要注意竞争和死锁相关的问题。
第三单元
第三单元主要是参考JML进行编程,JML是用于对Java程序进行格式化设计的表示语言,其用处在于开展规格化设计,使得交给实现人员的不是较为模糊的自认语言,而是逻辑严格的规格。在这一单元我认识到了优化架构设计的重要性,我一开始认为这一单元只是看懂JML并对其进行实现,然后就付出了惨痛的代价。
第四单元
第四单元主要是对UML的类图、顺序图和状态图的解析。通过编写解析UML的程序,我们也可以对UML进行更加深入的了解,从而加深对面向对象这一思想的理解。
测试与实践的演进
在OO的课程中,我经历了从对拍随机数据到手动构造样例肉眼检查再到对拍随机数据然后进行针对性测试和压力测试的过程。
在第一单元中,因为求导操作的特殊性,作业的对拍程序比较好写,所以我在第一单元的没一次作业中都进行了对拍,但是此时的对拍只进行了随机数据的对拍,导致我第一单元最后一次作业有一个边界性的错误没有被对拍检测出来。
到了第二单元,我觉得这一单元的正确性检查程序写起来比较困难,因而只构造了一些特殊情况的样例并进行测试,所幸这一单元没有出现很大的失误,而这也导致了我第三单元的拉胯。
第三单元中,我抱有侥幸心理,只测试了样例,肉眼检查了程序的正确性之后就没有再管我的作业,导致我的第一次作业出现了一个巨大的智障错误,此时我意识到了测试的必要性,于是在第二次作业中我进行了随机数据的对拍,但是这一次由于构架设计失误,我产生了超时的问题,由于对拍时使用的是随机的数据,所以没有检测出这个问题,于是第三次作业中我不仅进行了随机数据的对拍,还进行了每一个方法的压力测试以及手动构造出的一些特殊情况的测试。于是在第三次作业中,我如愿以偿的获得了100分。
之后就一直持续着完整的测试过程。在失败和爬起来的过程中,我的对拍程序越来越完善,也从一开始使用的没有那么方便的c++数据生成程序变成了python数据生成程序。学习到了程序不仅应该整体测试,还应该进行单元测试。
课程收获
在OO课程学习中除了获得了面向对象的思想,面向对象的各类知识,我还学习到了应该如何进行测试,如何给别人找bug,在程序规模较大的时候如何编写代码以保证程序可以被理解。在几次翻车中,我还意识到了测试的重要性。
另外,由于OO课程对代码风格的严格要求,我认为我的代码现在写的比原来更加容易被理解,在上这门课程之前我是一个大括号能不写就不写,变量初始化能缩到一句话里就缩到一句话里得人,这样的代码会给别人造成极大的阅读困难,而经过严格的要求,我认为我写出的代码结合一些注释已经变得比较容易被理解了。
三个具体的改进建议
1.希望给出实验的反馈/实验的标准答案
OO每一次实验做完了都比较慌张,因为一不确定自己是否真正理解了题意,二不知道自己的做法是否正确,如果实验有一个反馈的话,我认为可以增进我们OO学习的效果。
2.第二单元一二次作业间难度梯度可以加大
第二单元第一次作业和第二次作业的迭代我只修改了很少的代码,在一个小时之内就完成了,因为我认为第一单元和第二单元的本质没有差别,只是消费者从一个变成了多个。
3.提不出来了,我觉得OO真的是设置比较完整合理且友好的课程了
线上学习OO课程的体会
我觉得线上学习OO课程和线下学习OO课程应该差别不大(笑)
主要差别就是理论课和讨论课不是面对面交流,但是线上学习,也就是录播课的形式对我来讲是十分友好的,这样就可以自己把控学习的节奏,对于已经掌握的知识快速进行复习或者对于掌握的不是很好的知识反复学习。比较遗憾的是研讨课不是面对面交流,研讨的气氛还是差了一点。