随着第四单元UML第二次作业的结束,本学期的OO学习也宣告结束了(但还得写博客),下面就对本单元和本次作业做一个总结。
第四单元两次作业的架构设计
本单元是对UML的结构进行解析,第一次作业是对UML类图的解析,主要的难度是UML各种元素之间较为复杂的从属以及其他关系。我的类图设计如下:
我自己创建了ClassModel类来统领两个子类ClassClass和InterfaceClass,分别代表类和接口,其中实现了添加、储存、处理类和接口的各种下设参数的方法和变量,让类和接口的类继承同一个父类非常重要,因为类和接口有很多相似的地方,再进行输入处理时也有很多不易区分也不用区分是类还是接口的情况,所以这样处理极大地方便了程序对这两个类地储存和管理。对于方法我创建了OperationClass来添加储存和管理方法的各种属性,然后ClassClass和InterfaceClass就只用储存和管理OperationClass即可,对于其他的属性由于没有更多的层次,所以就直接使用接口提供的UML类来进行储存和管理即可。
在进行输入处理的过程中,由于其结构的层次性,应该将各种属性的UML_ELEMENT分批来处理,我首先识别处理了UML_CLASS,UML_INTERFACE,UML_OPERATION, UML_ASSSOCIATION_END, 之后再将剩余的其他属性进行识别处理,这样再识别时就可以直接建立起各种元素之间的逻辑结构。在储存中我主要使用了HashMap结构,进行从id到类,从name到类等的映射。
对于各种指令的处理方法,有难度的主要分为两类,一个是需要考虑关联关系的指令,对它的处理比较直接,在每个ClassModel类中均有其关联的类或接口的引用,直接访问即可得到所需要的信息。更复杂的是需要考虑继承关系和实现关系的指令,对于继承关系需要考虑多重的继承,所以我们使用递归来处理,其中Information类就是创建用来在递归时在类与类、接口与接口之间传递信息的,我们任意从某一个类开始,逐层向上,利用递归来实现与继承和实现有关信息的统计,储存在information里,再逐层向下传递。一次递归结束后,再找一个没有经历过递归的类开始递归,直到所有地类和接口都经历过一次递归为止。
第二次作业在第一次作业的基础上增加了状态图和顺序图的解析,以及对类图合法性的判断。在这里要感谢老师和助教们手下留情,最后一次作业的难度要比我想象中简单很多,特别是最后加了很多数据限制以后,整个问题变得很简单。
整体架构如上,对于顺序图建立一个Interation类来储存和管理对应的信息,对于状态图类建立一个StateMachine类来储存和管理对应的信息,相比类图简单很多,想法也很自然。
那么本次的难点主要在于类图合法性的检查,类似对类图的处理,我们按照层次顺序依次识别和建立各元素之间的关系,但不需要用到其他的类,只需要根据要求按照id和name建立关系即可。第一个检查较为简单,只需要遍历查看attribute和Association End有没有重复即可。对于第二三个检查,先将类继承,类实现接口,接口继承形成一张id为结点的有向图,那么第二个检查就是在有向图中找圈,具体地可以使用强连通分量等算法,但由于这里点比较少,所以我们对每个点跑一遍较为朴素的每个点只可到达一次的dfs即可,若可以回到本点,则将该点加入异常结果中。对于第三个检查,在第二个检查检查已经无圈的情况下,找任意两点之间有没有多于一条路经可以到达的情况,若有,那么起始的点就重复继承,具体地同样也是对每个点使用较为朴素地dfs,若在dfs中访问了某个点两次,那么这个起始点就加入到异常结果中。
四个单元中架构设计及OO方法理解的演进
在最开始的第一个单元,明显地自己仍然是面向过程的思维,当时应用熟练的只是Java的语法,而不是Java面向对象的思想,第一单元的第一次作业好像就只使用了一个类来完成了所有的事情,在第二次作业中让自己多分出了几个类,但仍然不够灵活和自然,更多的是为了划分而划分。
到了第二个单元,有了前面一个单元三次作业的练习,自己有所进步,开始从面向对象的思路开始思考,自己所处理的问题有哪些对象可以使用,他们之间又有哪些关系,但第二单元的重点我认为是在线程的设计和处理上,根据线程的理论,类的划分也就比较自然,但也是让我感受到了面向对象的便利。
在第三单元之中,是根据JML来写代码,更多地是在助教们设计好的架构下来补充代码,虽然没有太多的自己的设计,但这也是一个学习的过程。到了第四单元,对面向对象的理解应该已经有了比较高的进步了,可以从问题涉及的对象入手来分析问题,可以很自然地想到一个比较好的架构,并实现它。
四个单元中测试理解与实践的演进
第一个单元最开始自己测试的方法还是比较原始,主要是自己手动构造一些边际数据来进行测试,肉眼来看结果的正确性。在后面由于表达式难度的加大,肉眼很难分辨正确与否,所以我和几位同学一起用python来对拍,答案相同则认为正确。
第二个单元是多线程,在第一次作业中我吃了手动输入的亏,由于自己手动输入的速度太慢,所以基本上不会造成线程安全问题,所以隐藏了很多问题。所以之后我使用了bash批处理和Python来实现了自动生成输入,自动按时输入和检查输出的合法性,大大加快了检查效率,也使得在互测中方便了很多。
第三个单元中引入了JML,开始我还是使用自动数据生成和多个程序对拍的方法,之后也尝试了利用JML自动生成数据并自动测试,但总有一些bug,所以最后尝试使用了朴素的Junit单元测试,还是比较方便的。
第四个单元是UML的解析,由于数据不易生成,所以测试主要是利用starUML来生成一些边界性的数据进行测试,也由于UML的结构相对比较固定,所以还较为方便。
总的来说,测试是程序设计过程中一个非常重要的环节。经过四个单元,我认为测试最好的方法就是使用Junit对没个小单元进行功能测试,但实践中由于自己类和方法的设计问题以及时间问题,比较难以实施。同时自动化测试尤其是压力测试对测试也是一个必须的过程。
课程收获
最大的收获当然是面向程序的设计思想,面向对象提供给了我们一个程序设计的高效思路,使得我们的程序层次化架构更加清晰,代码重用更加便利,加快了程序设计速度,提高了程序设计效率。丰富了我之前单一的面向过程的变成思想,展现了编程更多的可能性。
在这个过程中自己的代码能力也有了很大的提升,也是第一次拥有了工程性的想法和思维。还学习到了多线程的程序设计,了解了Java较为底层的实现,对Java有了更深的理解。也学习到了规格化的设计,JML语言,UML建模语言等。
另外,在这个过程中,自己分析问题的能力,测试的能力,debug的能力也有很大的提升,也是对自己的抗压能力,面对较大规模编码的能力的提升。
课程改进建议
- 希望改进一下课上测试的形式和方法,至少找时间讲解一下课上的题目或给出参考性答案,否则我们在课上测试中得到的收获很少。
- JML部分课程组或许可以再进行一些探索和优化,删去一些难以实现的部分,增添一些更为实际的要求。
- 希望可以改进一下课堂使用的ppt,个人认为课堂ppt的逻辑普遍有一些混乱,结构不是非常的清晰,常常有一些重复等。另外,截图也经常看不清楚。