OO第四次单元总结——终局之战

紧张刺激的最后一次编程作业结束后,最后一次博客作业也终于到来了,这也是真正意义上的最后一次OO作业了,仔细想来OO陪伴我度过了无数个周末,经历了无数个不眠夜,终于要和它说再见的感觉竟然有点复杂,轻松、愉快,又有点不舍(我是不是有点受虐倾向~~~),可能和刚刚结束高考的同学们对高中的情感差不多吧(高考考生:啥?我没说过)。

那么还是照例先来看看这最后一单元的OO作业吧。

这次实现的是一个基于UML图的查询功能,具体实现起来难度并不是很大,但需要综合考虑的东西很多,一不留神就会出现纰漏,并不需要设计复杂的算法,对时间复杂度的要求也不高,但各种UML图的可变性较高,一旦理解不到位就会出现bug,而这种bug,往往是很难发现的。

在这个单元作业公布之前,我还以为是要根据给定的UML图设计自己的程序呢(就像JML那个单元一样),但事实证明我又猜错了,老师和助教们的想象力果然高深莫测,佩服.jpg。

构架设计

说实话,这单元的作业,可能才可以配称之为有一个还算像样的“构架”。以前的作业,虽然能很大程度上保证正确性,但在架构设计上的能力和付出的时间确实不足,这次可能得益于看了很多UML图,对于构架设计的方式有了初步的认识,也设计出了一个还看得过去的构架。

由于第二次作业中UML类图部分重用了第一次作业的代码,故只对第二次作业的架构进行分析即可。

如图所示,是这次作业中的整体框架,采用的是一种类似于工厂模式的结构,四个package分别对应四类查询需求,以初步降低不同UML图和查询指令之间的耦合度:

  • check:规则检查,即UML002、UML008、UML009
  • model:针对UML类图,负责与类图相关的所有指令
  • schedule:负责UML顺序图
  • state:负责UML状态图

而MyUmlGeneralInteraction类则负责与输入输出接口交互并将查询命令下放到上述四个package的相应位置。

接下来,就先着重讲解一下UML类图的架构吧,这也是最为复杂(可能也是最为重要的一部分)。

整体结构:

在model这个package下面共有5个类,MyUmlModel负责接受上级(MyUmlGeneralInteraction)指令并进行构图和查询(也差点突破了500行的限制),其余四个则负责辅助MyUmlModel完成构图和查询的任务(也有一部分的缓存功能)

Counter类负责统计不同类型的操作数量并保存下来

Father类负责统计某个类(以及接口)的全部父类以及记录顶层父类

那么有人可能会好奇,为什么我只给这两项任务的结果做了缓存,原因其实也很简单,对于Operation的查询而言,每一次查询其实需要遍历某个类下的所有操作,也就是说,有无返回值、有无传入参数其实已经全部统计出来了,再一次查询的时候,虽然指令不同也可以利用缓存结果;而对于父类的统计,就显而易见了,类图的查询需要用到父类的地方实在太多了,不缓存都不好意思了~~~

也就是说,我做了缓存的地方一定是查询指令不相同也可能用得上的,这也算是查询平均用时和构架复杂度的一个折衷吧(主要是指令太多,每一个都把计算结果保存下来太麻烦了而且可能用不上)。

而MyAttribute和MyParameter就很好理解了,保存了属性和参数这两种元素的一些信息。

因为我对于每一个输入进来的元素,只保留了有用的信息而舍弃了其他信息,属性和参数这两种元素需要保存的信息有点多,就新建了两个类,使整体构架更清晰的同时也降低了耦合度。

那么其他的信息保存在了哪里呢?

这显然是我构架中一个问题,将它们都保存在了一起而没有分离开来(主要是图个方便了)。

UML类图之后,再来讲讲第二次作业最为困难的部分(个人认为):Uml规则检查。

Uml002(类的成员属性和关联对端重名):这个比较简单,在构造方法中统计各个类下的成员属性和关联对端名即可。

Uml008(循环继承):这个我认为是最有难度的一个,我用的方式是对每一个类和接口dfs递归找继承,只要回到了自己就将这个类或接口纳入异常列表。

Uml009(重复继承):遇上一个类似,只不过多了一个接口实现,我将继承和接口实现在规则检查的构造方法中做了等价处理,也就解决了这个问题,这里我使用了bfs(其实dfs依然也可以),对于每一个类和接口一旦发现重复继承就将这个类或接口纳入异常列表。

其实状态图和顺序图就没什么好说的了,难度其实不大,整体结构和类图相似但更简单,那么就进入下一个话题吧。

架构设计及OO方法理解的演进

第一单元

第一单元是多项式的求导与化简,现在看来并不算难,但当时接触Java没有多长时间,面向对象的思维方式也没有完整地建立起来,因此完成起来也较为吃力,由于追求化简还炸了一个强测点,感觉有点得不偿失,这也在一定程度上说明了我的构架设计其实是很糟糕的。

仔细想一想,第一单元的作业中我还是做了一些构架设计的,但更像是为了构架而构架,没有起到解耦和降低复杂度、提高复用性和健壮性的作用。

第二单元

这一单元是多线程电梯作业,说实话,这一单元的作业还是比较困难的,尤其是多电梯调度的问题,但也正是在这个单元,我初步了解了OO的思想方法,明白了面向对象和面向过程的区别,也切身体会到了面向对象在解决问题时的简便(当然,这一点随着OS这门课的深入而愈发明显,大量的C代码真的是痛不欲生)。

对于构架,则采用了老师们推荐的分配器&电梯的方式,对于自己设计架构还有一些吃力。

第三单元

第三单元是JML规格,具体要求是构建一张动态线路网并进行查询,时间复杂度成为了同学们关注度较高的问题,由于这一单元规格化程度较高,具体难度在于一些算法的设计,与前两个单元有着较大的不同,因此是一种全新的体验,在这一单元中,我领会了OO的规格化思想,完善了我对OO的认识。

第四单元

UML图的解析,这是我第一次自主设计架构的尝试,感觉结果还不错。

其实,这四个单元看似独立有彼此联系、层层推进,每一个单元都教给了我不同的知识,让我对OO的认识以及构架的设计更加深刻。

测试理解与实践的演进

测试这个东西由于OO课程黑盒测试的性质而显得尤为重要。

第一单元

纯手工测试,本以为可以做到全覆盖,却还是有遗漏的部分,没有做到充分测试。

第二单元

前两次由于比较简单还是进行了手工测试,最后一次的多电梯采用了测评机自动化测评的方式(从此以后,我爱上了测评机~~~)。

第三单元

这一单元采用了JUNIT测试和测评机测试并行的方式,效果十分显著,没有被找出bug的同时还找出了其他人的bug。

第四单元

这一单元采用的是手工构图测试和测评机测评并行的方式,在第二次作业中测评机还找到了我Uml008规则检查的bug,还好及时改正了过来,不然后果可能较为惨烈。

设计模式

由于第一次博客作业中我对设计模式不是很了解,疏忽地漏掉了一部分这方面的内容,现在结合这四个单元的内容对采用的设计模式进行一个总结。

第一单元

这一单元我连设计模式是啥都还不知道,而且代码基本是面向过程的,就不谈了。。。

第二单元

由于我在多电梯作业中设计了三个分配器分别对应三个电梯,这是一种观察者模式的设计方式,共享对象(请求队列)和分配器是一对多的模式,分配器向共享对象发送订阅请求,共享对象随着每个电梯分配器的请求更新实时向每个分配器发送更新信息。

第三单元

应该也没有。

第四单元

前文也说过,是一种类似于工厂模式的结构,自顶向下发送请求信息,自底向上组装返回信息。

其实我对设计模式的认识和应用不够深刻,写代码时也没有特地考虑要使用哪些设计模式,今后还要继续加深对设计模式的认识。

课程收获

OO这门课,我的收获还是很多的,不仅学习了很多有关OO和Java的知识,结识了很多大佬,提高了编程能力与构架能力,更重要的是,进一步提高了我的抗压能力与临危不乱的能力(例:ddl前两个小时发现bug并改了过来,真的是惊心动魄),除此之外,这门课教给我的OO思想是最重要的,我一直认为,计算机专业的最精华部分是各种优秀精妙的思想,通过这门课,OO思想的萌芽已深深扎根,今后的学习和工作中,Java可能不是核心,但OO的思想会一直伴随着我。

改进建议

1.互测时,对于一些实际成功hack数较少的组,可以自动投放一些其他组成功hack的样例,帮助同学们发现bug。

2.对构架的训练不够充分,实验课是否可以考虑加一部分架构训练。

3.实验课从始至终都存在问题,一般都是上午讲课下午实验,实验任务的设计比较不合理,其实在很大程度上没有起到训练的效果,而且是否应该公布一下实验课的结果或者官方标答呢,要不然也不知道自己对不对。

4.指导书有一些不明确的地方,导致前期不敢动手写代码。

5.是否可以加入选作内容(例如对同组同学代码的点评)并给予一定奖励,以此鼓励大家多读其他人的代码提高自己的能力,不然大家都是直接评测机解决互测,感觉起不到很好的效果。

总而言之,今年OO这门课的的确确进步很多,相信在助教和老师们的努力下,OO这门课会越来越完善的。

到此,OO这门课结束了,但还有新的旅途等着我去探索(说的就是你,编译原理!)。

愿指引明路的苍蓝星为我们闪烁