BUAAOO-第四单元总结&课程总结-UML解析器

那一天我二十一岁,在我一生的黄金时代。我有好多奢望。我想爱,想吃,还想在一瞬间变成天上半明半暗的云。后来我才知道,生活就是个缓慢受锤的过程,人一天天老下去,奢望也一天天消失,最后变得像挨了锤的牛一样。可是我过二十一岁生日时没有预见到这一点。我觉得自己会永远生猛下去,什么也锤不了我。
——王小波,《黄金时代》


0 题目概述与博客说明

本单元作业的目的是基于课程组所给出的UML数据构造一个UML解析器,满足所需要的查询功能,此外,在最后一次作业中增加了UML合法性检测。

相较编程难度而言,本单元最大的难度是理解UML各元素所代表的含义。其中以第一次作业为最,需要课下阅读理解的内容很多;同时,从零开始构造一个新系统的难度要远高于后续的优化与增加新功能。因此,就我个人感受来说,本单元第一次作业的难度仅次于第一单元。

1 架构设计

本单元作业我选择的架构相对而言略显复杂,但可拓展性较高。事实证明,在第十三次作业确定的架构,一直到第十五次都没有任何改动,节省了我大部分的开发时间。我的总体架构是分了interaction和tree两个大类,每一个interaction关联一个特定的tree结构,用于管理对应的元素。

数据结构

tree结构内部的addTreeElm方法实现了对不同类型元素的管理,对每一种类型的元素,我实现了对应的Hander方法,以UmlClassTree为例:
image
对于可能会查询的元素,我分别构建了两个Map,Base用于存储(id, Elm)键值对,而Map则用于存储(name, Map<id, elm>)键值对。在构造对象时,我将同一个对象分别加入两个Map中,尽管这样比较繁琐,由于查询存在出现通过name查找和通过id查找两种,查询时会特别简便;由于两个Map中存储的是同一个对象,修改时只需要对任意一个进行修改即可,也特别方便。这里同样以Class为例:
image
此外,对于具有嵌套类型的元素,如Interface、Class包含Operation、Attribute等,Operation包含Parameter等,我为每个嵌套的父元素定义了一个新的类,其内部同样定义了Base和Map两个容器,用于存储相应的子类。
image
为方便元素的管理,我定义了一个接口MyElementInterface,让myelememts中的所有类均实现这一接口。对于Class和Interface,由于这两者含有的公共元素几乎一样,因此我让Class去继承了Interface。
image

算法实现

interaction结构则是实现了相应的查询函数与算法。由于我自己为大部分元素定义了新的类,因此查询算法就很简单了。比如getTopParentClass方法,我在Class中定义了parentClass,因此可以进行如下查询:

        while (umlClass.getParentClass() != null) {
            umlClass = umlClass.getParentClass();
        }
        return umlClass.getName();

此外,第13次作业中,我的getImplementInterfaceList方法是采用的BFS,但第14次作业中,在实现getSubsequentStateCount方法时,我意识到不管是接口的实现或是继承,还是状态图的后继状态,本质上都是图的合并,完全可以采用并查集的思想来实现。同时,第15次作业中的错误检测同样可以用到并查集的思想。这是我在一开始的构思中没有想到的,也体现了增量开发的优点。与传统并查集不同,本次作业同样采取的是经过优化的并查集算法,即我在第三单元博客作业中介绍的连通块合并算法,在此不再赘述,仅放出在State之间建立transition的例子,其中黑色箭头是已经存在的关系,蓝色箭头是需要建立的关系:
image
image
由于每个结点均含有本连通块的所有元素,因此在一些需要判断是否存在自环,或是需要遍历连通块内所有元素的场合非常方便。在判断是否重复继承时,由于已经存在所有的父接口的集合,可以利用集合自动去重的性质,只需要判断该集合的大小是否小于父接口列表的大小,若小于则必然存在重复继承。

2 架构与测试演进

Unit 1

第一单元给我带来的感受是最痛苦的,留下的印象也是最深的,那时我码力很弱,也不会测试,看到题目只能哭哭(呜呜呜),第一次作业我连夜码了一个有限状态机,仅仅一个方法就达到了300行,也毫无面向对象思想的体现;第二次作业算是勉强过了弱测和中测,却在互测中被hack了100多个点;到了第三次作业,鉴于前两次作业留下的💩一样的架构和逻辑,我手足无措,根本不知道从哪里下手……
总体而言,第一单元完全是面向过程的求导,而多项式的长度和嵌套层数不同,是无法简单用面向过程的思路进行描述的,因此我基于简单有限状态机的架构是很难描述这一过程的。

Unit 2

第二单元之前,我提前预习了多线程相关的知识,同时认真阅读了相关的设计模式,参考了课程组给出的实验课的代码后,在架构方面已经比第一单元清晰了很多,最终选择了生产者消费者模式作为主体架构。本单元作业主要的难点是线程安全性的维护和调度算法的选择。从这单元开始,我开始有意识地搭建自己的评测机,也借此hack了不少同学。

Unit 3

第三单元是最快乐的一单元,尽管只要阅读相关的JML规格就可以实现对应的方法,但我在这单元可以说是得到了最多的训练、思考与进步。我开始注意性能问题,主动学习并设计了图相关的算法;我和@王卓浩同学搭建了自己的第一个完全自动的评测机,尽管这一过程几乎是用python把课程组提供的Runner重新写了一遍,但这一过程中所练习的面向对象的思想,是之前紧凑的学习生活中很难体会到的。

Unit 4

本单元的架构很难说没有借鉴之前三单元所学习的东西。我将算法与数据结构分开,利用并查集的思想完成部分查询,这都是前几次作业给我留下的成长。尽管对其他同学来说,这可能是微不足道的一件事,尽管我错误百出,但我真的从OO课程中学到了很多知识。架构与算法设计在上文已经写的很详细了,在此不再赘述。

关于测试经验

对于写好的程序而言,评测机并不是必要的,但测试一定是必要的。我的测试方法由一开始的求助同学,到自己慢慢手搓数据,再到自动生成数据,再到自动评测,是花了一定的时间的。与数理基础相比,我不是一个很擅长写码的人,但能够看到进步这件事,就已经值得我去努力了。构造数据时,可以尽可能选择边界数据。此外,在进行增量开发时,一定要满足新的程序可以通过之前程序的所有测试数据。

3 课程建议

1、确定一个合适的ddl,今年的课程时间设置感觉很折磨人。比如周三晚发布作业,周日截至,看似时间很充足,但周三晚、周四、周五都有课,留下的都是零碎的开发时间,留下来的只有周六周日完整两天,而周一只有一节航概课。对于我这样没法在其他课上专心做不相干的事情的人而言,是一件很痛苦的事情。此外,互测的时间与OS高度重叠,周二几乎满课,很难抽出合适的时机来阅读其他同学的代码,大多数情况下只是选择了一两个“幸运儿”,用自己写的评测机跑了几组数据。强烈建议OO课程组依照学生课表设置一个相对合理的截止时间。

2、减小第一单元的开发难度。第一单元难度过大,我认为即使放到现在来说,仍然是难度最大的一单元。而后续几单元的某几次作业难度很小,完全可以合并在一起,富裕出来的时间留给第一单元,不用强行为了每单元三次作业这种强迫症而分配任务。我认为第一单元合适的任务量是4-5次课下作业,一来寒假做的那些pre难度过低,不足以支持多数同学“体面地”完成作业;二来新学期新课程,给大多数同学一个课程的适应期。

3、希望理论课增加一些更加贴近实验课的内容。教学应当是“循循然善诱人,博我以文,约我以礼,欲罢不能”,带领大家感受增量开发的快乐,在这一过程中学到很多知识,而不是一股脑扔给大家很多资料,让大家在痛苦中培养自学能力(并不是说要降低课程难度,而是说明明可以有更好的方法解决这一问题,为什么非要选择最折磨人的那种)。坦白来说,本学期我的所有代码知识都是自学而来的,理论课几乎没有带来提升。对于巨佬来说,这种情况很正常,但对于我这种中等偏下程度的学生来说也是这种情况,我认为课程组是需要进行相应的改进的。

4、多线程电梯的一些改进思路:我做了一个完整的pdf,里面分析了一些评测指标和题目改进的思路,感兴趣的可以点击此处下载。

4 感想与收获

张华考上了北京大学,在化学系学习;李萍进了中等技术学校,读机械制造专业;我在百货公司当售货员:我们都有光明的前途。


实话说,OO课程给我留下了很多痛苦的回忆,但这并不是我推卸自己责任的理由,我时常在想,如果我更努力一点,如果我更细心一点,结果会是怎么样。与巨佬们相比,尽管我仍有很多不足,但正如上面说的那样:“我们都有光明的前途”。除了几个由于自己不细心导致的bug,其他那些bug是真的已经到达当时我能力的极限了。坚持了这么久,也算是有一些收获,希望以后会更好吧!
image

posted @ 2021-06-23 00:53  Stanlei  阅读(68)  评论(0编辑  收藏  举报
// 侧边栏目录 // https://blog-static.cnblogs.com/files/douzujun/marvin.nav.my1502.css // // // // // //