OO第四单元作业总结暨完结撒花

OO第四单元作业总结暨完结撒花

终于,在漫长的一学期之后,OO课终于迎来了完结的曙光。看到朋友们在朋友圈慨叹一路下来没有任何bug,在课程结束的颁奖典礼上我发现众多的奖项之中我竟一无是处,或许我不是OO这门课的胜利玩家,但我同样很感激OO课程带给我的成长与进步。从面对问题一main到底甚至无从下手的小白,到具有一定工程能力考虑架构设计的OO人,我很开心。

本单元的两次作业要求我们完成UML图的解析工作,这对我们更好的理解UML图具有十分重要的意义。本单元的第一次作业我们对类图进行解析,第二次作业中加入了状态图和顺序的解析和一些简单的有效性规则检查,我也在写代码的过程中对UML图加深了理解(知道了UML图不是个简单的画图)。

一、本单元两次作业的架构设计

作为OO课程的最后一单元代码作业,这也是一个学期检验自己面向对象思想和架构设计的地方,其实OO的每次作业,我都有意无意中注意着自己的架构设计(只是可能结果不尽人意)。

这是两次作业的关系,简单来说,第二次作业是在第一次作业上扩展了有效性判断和对顺序图和状态图的构建和查询功能。

第一次作业

  • 这次作业的逻辑较为简单,通过继承UmlInteraction接口实现自己的MyUmlInteraction类,其中对不同的UML类图中的元素封装出一个MyClass类。
  • MyUmlInteraction类中保存所有的数据结构,MyClass类中保存所有与类相关的数据结构。

  • MyClass类和MyUmlInteraction类中的相关数据结构

    • MyClass类中存储这个类对应的UmlClass类和它相关的属性和操作信息,它的父类和直接实现的接口
    • MyUmlInteraction类中存储在解析mdj文件中所有有用的信息,包括类的信息、操作的信息、接口的信息、继承关系等等。
  • MyClass类和MyUmlInteraction类中的相关方法

    • MyClass中的方法主要为设置其数据结构的set方法和访问其内数据结构的get方法
    • MyUmlInteraction类中的方法主要包括将解析的mdj文件中的元素信息添加到对应的数据结构中进行保存
  • 本次作业的查询指令的实现方法

    • 采用dfs方法,在每次查询一个类的相关信息时,同时更新它直到它的顶层父类的所有属性信息、关联信息和顶层父类信息,并将查询的结构保存在MyClass中,将MyClass类中的state布尔型量设置为true,之后查询这个类的相关信息时不会重复查询。
    • getClassAssociatedClassListgetClassAttributeVisibilitygetImplementInterfaceListgetInformationNotHidden方法都是通过循环遍历到顶层父类,然后在遍历过程中将相关信息加入到最后待输出的结果中。

第二次作业

  • 本次作业看似十分复杂(其实也十分复杂),其实逻辑关系仍比较清晰。对本次作业我的体会是状态图和顺序图的概念难理解但实现不难,但有效性判断的概念很好理解但实现困难。

  • 这次作业中要求我们通过实现UmlGeneralInteraction接口创建一个MyUmlGeneralInteracion类,要求我们实现的接口实际是通过继承四个接口而来,而每个接口中要求实现的方法其实分属不同的领域。为此,我们对应要求实现的四个接口创建了四个不同的类,每个类相应地用来实现不同接口中对应的方法。

    • UmlClassModelInteraction --> MyClassModelInteraction
      
    • UmlStandardPreCheck --> MyStandardPreCheck
      
    • UmlCollaborationInteraction --> MyCollaborationInteraction
      
    • UmlStateChartInteraction --> MyStateChartInteraction
      
    • 因此,在主类MyUmlGeneralInteraction类中我们通过创建了四个不同类的对象实例来实现了四个接口中对应的不同类的方法。

  • 对应类图、状态图和顺序图分别封装了MyClassMyInteractionMyStateMachine三个不同的类用来存储与其相关的数据结构。

  • 在对mdj文件解析后的所有信息都保存在MyElementContainer容器中,将MyElementContainer容器传到对应的不同类的构造方法中,使得相关类可以访问容器中的所有数据结构。

  • 本次作业的查询指令,在第一次作业扩展的基础上增加了对状态图和顺序图的查询,第一次作业对类图的查询实现方法不变(封装到MyClassModeInteraction类中),其他的查询方法也不难。

  • 本次作业有效性判断的方法

    • checkForUml002方法只需检查属性和关联对端名是否重复即可,较易实现;
    • checkForUml008方法,对循环继承的类的判断较为简单,因为类只能单继承,所以循环保存遍历的类,当发现本次到达的类在之前遍历类的列表中出现过则说明这个类循环继承;在判断接口的循环继承时,由于接口可以多继承,因此实现起来相比类的循环继承较为复杂,我才用的是dfs方法,即递归深入保存递归过程中路径查询过的接口,当本次到达的接口在之前出现过时我们认定这个接口循环继承,然后一层层返回退出。
    • checkForUml009方法,查找重复继承接口的类和接口。首先查找重复继承接口的接口,通过bfs方法首先将接口直接实现的所有接口加入到队列中,然后从头到尾遍历队列,将每个接口通过继承实现的接口再加入到队列中,当队列中有重复元素时说明此接口重复继承;然后查找重复继承接口的类,类的重复继承总体可分为两种情况,一种是类实现的接口中包括重复继承的接口,一种是类实现的接口中重复实现。

二、四个单元的架构设计及OO方法理解的演进

我觉得从推倒重来式的架构设计到最后一次写出觉得比较满意的作业架构,中间的成长是不言而喻的。

第一单元作业

第一单元作业是对正则表达式的处理,由于第一次作业时需要我们自己处理输入,所以其实对输入的处理也是十分重要的一个环节。在第一次作业中,我将因子封装为四类,幂函数因子、常数因子、三角函数因子和多项式因子,每类因子都实现一个求导方法,所以我们将求导封装为一个接口。

由于刚刚接触Java和OO,所以第一单元作业中架构设计体现的不好。这单元的前两次作业都是直接对正则表达式的处理,没有抽象出不同类的因子,我还清晰记得当时在写第二次作业时群里有大佬讨论将不同的因子封装为不同的类,但当时觉得能力有限于是采取的是面向作业编程的方法,前两次作业较为轻松地完成,然后写到第三次作业时发现作业变得非常复杂,于是几乎是采取了推倒重来式地架构设计。

第二单元作业

第二单元作业是完成多线程电梯,这单元作业完成的很不顺利,主要是自己接受多线程知识时有些吃力。

和之前一样,本单元的第一次作业很简单,由于当时自己对多线程理解不深,所以为保险起见我其实是采用单线程完成了第一次作业(现在想来就是非常后悔.jpg),第二次作业时就不得通过多线程实现了,这时候对单例模式、生产者、消费者模式有了更好的理解,所以其实第三次作业在第二次作业基础上重构的力度并不是很大。总体来说,在作业中分为输入线程和电梯线程,采用生产者、消费者模式,输入线程作为生产者,将输入的请求放入调度器Dispatcher中,然后由调度器去调度不同的请求分配到不同的电梯线程,电梯线程Elevator作为消费者,最终停止的条件是所有线程均结束。

第三单元作业

第三单元是对对JML规格的理解,在我们的课下作业中是通过读规格来完成代码而不是写规格,所以在完成作业的过程中深切体会到了JML规格带来的便利。

可见,这个单元的每次作业的关联其实十分紧密,如果有较好的架构的话实现起来不是很复杂,我前两次作业写的还好,但第三次作业修修改改的地方太多了,而且“拆点”和“不拆点”的方法选取不当导致全面翻车,在经过强测爆炸后在修复bug阶段我重构了一个自己满意的代码。

第三次作业的查询指令都是通过floyd算法实现的,因而实现了一种算法、不同建图方式的统一,计算最短路径长度也使用的Floyd算法,add和remove指令用来更新数据结构。

附三个单元的分析:

第一单元作业分析

第二单元作业分析

第三单元作业分析 

三、四个单元中测试理解和实践的演进

我觉得自己的测试做的挺失败的,我觉得也正是因为测试没有做好,所以自己的bug都很多。构造测试点挺考验能力的,要求测试全面覆盖,有时候觉得自己写出的程序没有问题了,但是经不起测试。我之前采取的测试方法往往都是看程序理逻辑,但理自己程序的逻辑往往又会陷入错误的思维当中。最后一单元的第一次作业,我体会最深的一点就是之前写的简单对拍器都是在互测阶段去拍别人你的错误,但我当时才意识到其实最该测试的是自己的程序,真的非常后悔。对自己的程序过于自信的结果就是测试不充分、不全面。所以最后一单元第一次作业提交后真的是有史以来最自信的一次,因为课下经过了很充分的测试。

第一单元正则表达式的测试点主要从两方面,一方面就是正则判断上有没有遗漏的点,第二就是像省略这种问题容易出错误,所以第一单元的作业从测试到互测完全都是自己手动构造样例,包括找别人bug也是通过读程序定点突破;之后的测试由于程序复杂度增加,而且不存在对输入处理错误的问题后,在测试自己程序的时候主要是通过构造样例,而在互测阶段都是通过简单的对拍器更好的找到别人的错误。

所以最后通过测试最大的收获就是一方面写对拍器的能力真的增强了(python和bash),另一方面在理其他同学写的程序时大体逻辑能更快的理清,也能相对准确地找到可能哪里会出现问题。

四、课程收获

  • 充分测试:充分测试是正确性的保证,在测试不全导致的因为很小错误翻车的真的跌了不少跟头。
  • 功能实现前不考虑性能问题:前两个单元的作业有性能分,后面的作业虽然没有了性能分,但是也要很注意时间否则可能会超时。在开始写作业的时候往往写程序时候考虑的问题很多,考虑多了实现起来就容易出错,但同时写完作业后经过优化也常常会出现不少bug,所以性能真的是一把双刃剑,量力而行即可,不要过分追求性能而丢了西瓜捡了芝麻。
  • 架构:重视架构的设计,不要着急程序的实现,架构搭建的好能在之后扩展功能时省掉不少麻烦。在刚开始写作业的时候通过推倒重来真的费了许多事,到后面也能体会到架构好带来的优点,这也是OO课程我们应该学到的很重要的东西。
  • 面向对象思想:这是本门课程的核心,面向对象和面向过程相比,面向过程重视过程的如何实现,面向对象则更好地体现封装,将不同的功能封装到不同的类中。

五、立足于体会提出三个具体改进建议

  • 合理安排上机时间。我们这学期的上机时间安排在理论课的当天下午,对我这种慢热型选手来说,经常是知识没有理解或者即使理解也不会应用就开始上机,我觉得这种安排极其不友好,当然课程组在本学期之后安排的上机相比前两次来说难度已经降低。
  • 增加测试点。对于中测一时爽强测火葬厂的选手来说,真的十分痛心,所以当听到吴际老师在讲到明年的课程改革时提到在课下作业环节可以每个人提交上去自己的数据供大家一起测试,我认为这真的是非常人性化的设计,不至于让我(们)在强测环节死的太惨,有效提高自己程序的正确性和抗压性,达到多赢的效果。
  • 关于网站一个小小的建议,在作业提交后可以看到自己最后提交的版本。(对于强迫症患者来说有时担心最后提交的版本不是自己最后push上去的版本,现在网站可以显示所有push上去的版本但不能显示最后提交的是哪个版本)

最后,虽然OO这门课还有有待改进的地方,但通过这门课我真的学到很多,我们可以看到OO课程的改革带来的进步,衷心希望这门课程原来越好!

 

原文地址:https://www.cnblogs.com/flying-rabbit/p/11079583.html