OO第四单元总结
面向对象第四单元总结
作业架构设计
-
第一次作业
本单元的作业是完成一个自己的对于UML类图的解析器,根据官方提供的mdj文件解析工具,将其解析为输入输出接口可识别的格式,而我们只需要对于这一文件包含的类或接口的一系列诸如属性方法的内容进行分析即可。
在第一次作业中,我们仅仅需要对于类图进行解析。由于以为内容并不是很多,在这一次作业中,我傻傻地将所有内容全部放在了需要我们完成的MyUmlInteraction类中,而不是新建例如接口类,类类,属性类这些类来获得更加清晰,更加面向对象化的程序。最后这也导致了该类的行数远远超过了checkstyle要求的文件行数限制。
在存储类图相关信息时,我采用了很多的HashMap和ArrayList容器,即在我们在输入端将所有的信息全部输入进去后,通过调用我们MyUmlInteraction类的构造方法,将这些一条一条的信息全部按照规则存储到我们的容器中,根据访问容器中存储的内容我们可以轻松地获得例如继承,类,实现这些内容,而在下面完成接口函数时也可以比较轻松。举个例子来说,存储类时,首先我用一个HashMap以Id为key,以UmlClass为值保存了所有的Class,接着用一个HashMap以UmlClass为key,以ArrayList<UmlAttribute>为值对属性进行存储,这样我们就成功地将类和属性的信息进行了保存,方便了后面的使用。对于方法和参数的存储方法也是类似的用HashMap和ArrayList进行组合存储。至于类的继承,关联关系,接口的实现,同样也只需要使用HashMap按照一定的方法进行存储就可以记录下所有的信息。我所采用的所有容器如下图所示,没写注释,但还是挺好理解的。

在存储完这些类图的信息之后,我们需要完成的接口函数其实就是对于容器中的内容进行查找分析,其中我个人认为比较困难的还是getImplementInterfaceList这一函数,这个函数表面上看只需要找到类实现的接口,实际上我们还需要考虑类和接口的继承关系,尤其是接口还能够多继承,我一开始就没有注意到导致强测出现了Bug,事实上,对于接口的多继承,我们可以在存储信息时就增加一个容器来保存一个接口的所有父亲,包括直接继承和间接继承的,这样的好处在于不用在后面进行递归查找导致超时的问题。
-
第二次作业
第二次作业是在第一次作业的基础上进行了增量式开发,需要我们除了对于类图进行解析,还需要我们的解析器能够对于状态图和顺序图进行解析,在这一次作业中,我吸取了上一次作业中的教训,没有继续将所有的内容都堆在MyUmlGeneralInteraction类中(虽然上一次作业的内容由于懒没有重构),而是对于状态图的解析,新建了StateMachine类,State类,Transition类,对于顺序图的解析,新建了Interaction类和Lifeline类。其中StateMachine类是状态图的顶级类,其不同的实例代表了不同的状态机,State类则在StateMachine类下,代表了状态机下的不同状态,而Transition类则能够表示不同State之间的转换。我们使用这样实例化我们的类的方法而不是像第一次作业那样完全只使用容器来存储信息,我们只需要在MyUmlGeneralInteraction类中使用一个存储所有实例化的StateMachine的容器即可保存下我们状态图中所有的信息,同时,我们需要完成的接口函数也可以在我们自己写的类中完成,在外部只需要调用这些函数即可,大大减少了MyUmlGeneralInteraction类的行数,相较于第一次作业,这才是比较合理的架构。同样地对于顺序图的查询,由于本次作业中只需要考虑收发消息的条数,我们只新建Interaction类,其实例表示某张顺序图,Lifeline类,其实例在Interaction类下,相互之间发送消息,对于如何计算收发消息的条数,只需查找实例化的Lifeline类下的收到消息和发送消息容器的大小就好了,还是十分简单的。
-
第三次作业
第三次作业继续在第二单元的基础上进行增加内容,本次作业需要我们在所有信息输入后对于上述三种图类图、状态图、顺序图的有效性进行检查,说是进行有效性检查,其实质还是对于输入信息进行保存后进行查找分析,所以本次作业与第二次作业相比架构设计基本上没有什么改变,对于循环继承和重复实现这两个有效性的检查,是关于有向图的查找问题,对于这一类的问题,我们可以采用第一次作业中所阐述的方法,使用一个HashMap,以每一个Class为Key,以一个HashSet<Class>为value,用于保存类所有的父亲(包括直接继承和间接继承),接口也是一样,有了这样的一个容器,我们对于这样例如循环继承和重复实现的检查会变得比较简单和清晰,不用在检查时再进行各种DFS,BFS迭代查找。
对于架构和OO方法理解的演进
本课程一共分为四个单元,随着学习和作业的推进,我们对于面向对象以及程序架构方面的理解逐渐演进。
从第一单元开始,第一单元的内容是实现对于复杂的字符串表达式的求导。虽然说是第一单元,对于很多人还是第一次接触面向对象编程,本单元的作业一点也谈不上过渡或者是入门,难度还是挺高的。在第一次作业中,我就花费了大量的时间,由于对于面向对象思想还不是很熟悉,写的完完全全是一个面向过程的程序,而到了第二次作业增加了嵌套以及三角函数求导后,这样面向过程的程序好像并不是很行得通,在研讨课后,我了解到了递归下降这一方法,这种方法将表达式分成了各种因子的组合,并不断向下求导,很好地体现了面向对象的思想,而在这之后我也对于自己的程序进行了重构,对每一种因子建立类,分别实现各自地求导方法,再进行递归下降式的求导组合,这样写出来的程序十分清晰,而且具有很好的拓展性,这也可能是我第一次使用面向对象的思想来编程,同时体会到了一个好的架构的重要性,在看见要求后,我们不应该急于动手开写,而是首先应该考虑好程序的架构,让我们的程序拥有良好的可拓展性,否则到之后重构所花费的时间可远大于我们考虑架构所花的这一部分时间。
接着来到了第二单元,关于电梯的多线程编程。多线程编程在这个单元之前是真的从来没有接触过,完全不了解,第一次作业自然也谈不上有什么架构,程序能够跑起来就算成功。到了第二次作业中,由于上一周的上机课,课程组很贴心地为我们展示了多线程的好的架构和写法,在这一次作业中,我根据上机程序的代码架构对自己的程序进行了重构,对于程序的输入和电梯的运行分别建立两个类,这样假如我们的电梯要加上一些限制,直接在类中进行更改即可,这体现了面向对象的编程思想,在架构方面,对于输入线程和调度线程对临界区指令的访问,我们采用一个调度器对临界区内的指令进行管理与分配,这样我们的程序会拥有较好的可拓展性,不同的,例如在本单元中Morning、Random和Night模式的不同,就可以在调度器的调度方法上得到体现。在第二单元的学习后,我除了对于多线程编程有了一定的了解以外,更加重要的是对于面向对象的编程思想和良好架构的重要性有了更深刻的认识。
第三单元是JML语言,本单元属于是比较简单的一个单元,只需要我们根据JML语言的描述实现相应的函数接口,完成特定的功能即可,正好这个单元的时候操作系统实验正好写到比较麻烦,需要花较多时间的部分,这一单元属实是让我们稍微轻松了一下。虽然内容简单,只需要我们读懂JML规格完成函数,但是本次作业仍需要我们拥有良好的架构以规避超时等问题,可见良好的规格是无论何时都需要的,除了良好的规格,本单元作业也提升了我们对于图模型的处理能力,本单元设计的社交网络就是一张图结构的网络,通过本单元的学习,我对于图的相关算法有了一定的掌握。总之,本单元JML语言相对简单,但是对于JML语言的学习让我们对于规范化的代码有了更深层次的理解,JML语言可以很好地规避自然语言容易出现的二义性。
最后就是这次的第四单元UML类图解析器。本单元的难点在于我对于UML图的层次机构并不是十分了解,在搞清楚各层次关系时花费了较多的时间。正如我在上文中的架构分析中所说的那样,第一次作业由于没有考虑好架构就开始写,并且并没有体现出面向对象的编程思维,写出来的代码十分臃肿,而且不利于拓展,而到了第二次作业中我采用了面向对象的编程方式,将图模型中的各个层次分为不同的类来进行处理维护,这样的架构让我在第三次作业中进行拓展时比较轻松,可见良好架构的重要性。
总之在这四个单元学习下来,感觉架构是无时无刻都很重要的,每个单元中第一次作业中一个好的架构能让第二第三次作业变得轻松。至于OO方法,个人感觉就是对于逻辑层次关系进行对象设计,拥有比较清晰的层析,而面向过程就是关注程序处理事件从头到尾的一个过程,无法体现层次关系。
对测试理解与实践的演进
在测试方面在本学期中其实我并没有什么演进,本学期四个单元作业的测试我都是采用的手动或自动地构造一些数据测试或和与其他人对拍来完成的。
当然构造数据也要有目的地进行构造,例如第一单元,我们就可以构造一些比较特殊边界样例或者多层嵌套,数据不需要复杂,只需要看求导出来的组合形式正不正确,来判断对于各部分求导之后的组合正不正确。对于不同的因子,可以分别构造不同的因子字符串进行求导,来看看各因子自己的求导方法是否有错误。
至于第二单元,我们可以自动生成一些数据(指令),然后使用命令行来进行分时输入来测试自己的程序,总的来说,这个单元测试比较困难,我有蛮多的Bug都没有测出来。
到了第三单元,我还是使用随机生成指令,接着与他人的程序进行对拍的方法来完成测试的。
最后是第四单元,本单元我们可以使用课程组下发的mdj文件,按照课程组提供的方法将其转化为特定格式的输入,进行测试,由于这个构造数据难度比较高,所以我个人并没有怎么进行测试,主要还是靠弱测和中测的数据点找Bug的。
课程收获
在一学期面向对象课程的学习以及四个单元十二次作业的历练后,虽然确实很辛苦,基本上每个星期都要写很长的而且颇具难度程序,但是收获还是挺大的。
首先肯定是自己的编程能力获得了实打实的提升,以前大一,学习程序设计和数据结构的时候,感觉自己写个一两百行的程序都比较吃力,而且Bug很多,而在这个学期,每个星期都要写几百行的程序,这对于我的编程能力和自信方面有了较大的提升。
然后是在面向对象编程方面,我在一定程度上掌握了面向对象的编程方法,拥有了面向对象化的思维能力,学会了如何根据层次区分对象并分别封装成类。
接着是相关的编程和算法知识,本课程的研讨课同学们的分享可以让我了解到很多有用的编程相关知识和一些好的算法,例如第一次作业的递归下降,第二次作业的工厂模式等等。
最后正如最后一节总结课上所说,这门课让我不再像以前那么拖延,每周的任务不断,如果拖延地话很可能来不及完成任务,所以在本学期我作业基本都是尽早完成,不是等到DDL前再疯狂补。
对课程建议
- 个人感觉本课程作业难度还是比较大的,尤其是第一单元和第二单元,在寒假期间的Pre部分,课程组针对第一单元字符串方面的知识给我们了一定的练习,但是对于我们完全没有接触过的多线程编程完全没有涉及到,建议课程可以在Pre部分新增对于多线程编程方面的知识预习。
- 不能理解为什么弱测和中测有一半的点不给数据,如果是怕同学根据测试数据针对输出,可以稍微标识一下该数据点测的主要是什么内容,无法通过可能是因为什么地方有问题,这样什么都不给毫无目标地找Bug实在是很折磨。
- 修复Bug行数限制可以稍微增加一点,不然每修一次基本都要写说明,助教还要看和通过也挺辛苦的。

浙公网安备 33010602011771号