BUAA-OO-第四单元作业总结(UML图分析器)

BUAA-OO-第四单元作业总结(UML图分析器)

前言

      时光飞逝,光阴如梭,一个学期就这么从我的手里溜走了,以前听说的OO神课也算是真正结束了,有的时候都难以置信,最开始连Java都不会用的我也能翻越“昆仑山”,征服了四个单元的OO作业,这就是本学期最后一次的OO博客作业了,一方面总结一下第四单元的设计思路,另一方面也来回顾一下往昔“峥嵘岁月”,总结一下一个学期以来的学习感受和收获,话不多说,下面进入正题。

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

1.第十三次作业

       本次作业类图如下所示:

       其实与他人的交流过程中以及在阅读讨论区帖子的过程中,我发现好多人都是自己重新写了MyClass,MyOperation等类利用继承关系来重新建立UML元素,在这上面我就很偷懒了,并没有对这方面做出什么处理,而是使用了大量的HashMap来表示不同元素之间的关系,在解析的过程当中就存储好,然后在查询过程中直接使用,主要以树(其实也可以看作是图)的形式来组织数据结构,主要的遍历操作采用了前序遍历,都是使用dfs来处理,写起来不算困难,我认为更难的问题还是对于各种元素之间的关系上,什么元素内部包含哪些其他元素,能有几个,这就直接影响了HashMap如何使用,最好还是要依据UML图来辅助理解,个人认为最不好办的还是Association和AssociationEnd两种,在判断对端的类的时候需要找到结点,然后找到关联关系,然后找到另外一个结点,这才算找到了另外一个类是什么,处理起来相对复杂易错,需要格外注意。

       由于本单元作业都没有互测,强测顺利过关,姑且认为没有问题,唯一需要注意的就是空指针问题,也就是在查询的时候要先判断HashMap中有没有相应的Key存在,否则会出现报错,这个问题我过了好几遍筛子才算彻底解决,在之后的扩展当中也注意了这个问题,就没出现相应问题。

2.第十四次作业

       本次作业类图如下所示(空间所限故略去方法):

       可以看出,本次作业基本上是沿用了上一次的作业,除了增加了对顺序图和状态图的处理外,还使用了工厂模式,将对三种图的处理分别封装成类,在主解析器中分别调用相应的方法来返回结果,其他的均没有大的变化,包括数据组织形式以及存储形式,依旧是大量的HashMap(主要是真不想重构了,另外还是担心正确性的问题),新增的方法难度反倒不如上一次作业,写起来非常简单,比较难的也就是个无脑dfs可以解决的(其实可以加个缓存之类的加速查询,但是因为数据量不大所以并没有这样做)

       这次作业强测也没有出现问题,实现起来也没有遇到什么困难,比较顺利。

3.第十五次作业

       本次作业的类图如下所示(空间所限故略去方法):

       这一次作业增加了一致性和正确性检查的内容,增加了一个检查是否有错误的类处理,还是工厂模式,后四个标准实现起来比较简单,前面四个由于涉及到图操作,略有一点难度,思考起来最难的是R001这个错误,主要是感觉指导书上没有样例辅助理解,解释的也不太清楚,最开始有理解上的错误,但后来意识到类图关联对端的结点是属于该类的这一点,这个错误就很好解决了,R003和R004分别针对重复继承和重复实现接口,我采用了dfs和bfs两种方法分别实现了他们,问题也不大,最搞人的还是R002这个,找循环继承,当然还是普通的dfs可以解决,我是用的O(n^2)的懒人做法,每个点都遍历一遍看看能不能回到自身,理解起来不算困难。

       但是这次作业还是有了遗憾,强测爆了一个点,没能达成单元无伤的成就,主要就是R002的问题,我最开始是想找出一个点的所有环路,然后遍历所有点,但这样的复杂度太高了,而且很没有必要,后来就改成了判断每个点是不是在环路里面,能否回到自身,这样时间复杂度就降了下来,解决了这个问题,还是对于程序复杂度分析判断不足,采用了不合适的算法,这是以后需要注意的,要首先判断能不能将一个问题转化成一个更简单的形式,而不是直接上来就莽,这是我要锻炼的能力。

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

1.第一单元

       这一时期由于是刚刚接触了Java语言,一方面是要让同学们尽快熟悉Java语言,另一方面是要同学们初步认识到什么是面向对象的设计思想,它与面向过程的设计有什么不同,以及如何进行面向对象的设计,主要讲了简单的继承关系和接口实现关系,同时介绍了基础的工厂模式,在作业的完成过程当中,正确使用这一模式能够达到事半功倍的效果,还有就是功能的分类以及类的划分,把一些行为抽象成属性和方法,创建一个单独的类,同时保证最少功能的原则,让一个类就做一件事或一类事,这样可以最大程度地减少复杂度。此外就是了解迭代设计,留出扩展设计的空间,重视架构的设计,可以说虽然是第一单元,任务就不轻松,而且为后续单元打下了基础。

       这一单元三次作业,在我看来,是四个单元中难度最大的,连多线程也比不过这一单元,由于架构设计的问题,我是次次重构,才算是度过了这一单元,主要的想法就是根据多项式的特点划分出不同的因子,比如常数、X函数、三角函数等等,将他们分别设计成类,同时建立工厂类和求导类,将正则表达式划分出来的因子进行分别求导,将多项式也看成是一个因子,这样就可以支持嵌套求导,同时设置专门的格式检查类观察是否符合多项式的格式,同样是正则表达式处理,最后我是彻底放弃了化简的工作,才算是做出了第三次作业,强测也没能全部通过。求导看似简单,实则处理起来非常麻烦,要建立表达式树,化整为零,才能够完成求导的任务,这也是这一个单元的难点所在吧。

2.第二单元

       这一单元主要就是多线程的问题了,电梯调度的模拟,本质上还是生产者-消费者模型,这就是一个基本的设计模式,也不像第一单元那样需要费尽心机去构造类,继承实现接口什么的,电梯作为消费者,输入作为生产者,调度器作为中间存储,这就是一个很基本的设计,不是非常困难,三次作业我都沿用了这样的设计,算法上如果不是非要追求性能分的话,LOOK算法完全够用,由于数据是随机的,测试结果也很让人满意。

       个人认为这一单元一方面是要让我们理解多线程的操作,学会锁的运用,保障程序运行的安全性,避免出现死锁活锁等严重的问题,另一方面就是让我们了解了一些常用的设计模式,设计模式都是前人总结出来的套路,正确理解这些套路,在编写代码的过程中就会轻松不少,尤其是多线程的问题,本来就不是很容易理解,倘若连最基础的设计模式都要自己造轮子的话,那我估计周二到周六这几天是造不明白的,那就要无效作业了不是?

3.第三单元

       这一单元主要就是介绍了JML语言,并且要依据给出的JML来进行编程,一方面锻炼了我们理解JML的能力,另一方面也要让我们不拘泥于给出的格式,在理解注释的基础之上灵活处理,自己再次进行架构的设计,这样才能够很好地完成任务,一味地按照JML无脑写出来的代码肯定优雅程度就不够啦。

       但是惭愧,这些都是我马后炮的认识,真的写代码的时候我还就按照JML无脑处理了,我看了看他人的代码,好多人都单独创建了图类来进行处理,不是将输入的数据直接存储,而是进行了初步的分类处理,我就没有做这些工作,基本就是Person, Network, Group三个主要的类,用邻接表存储社交网络,同时设置一个SearchNet类来进行诸如图遍历等操作,只有第三次作业才加入了Node类来进行最短路径的查询工作,其实完全可以第一次作业就把Node类写出来,这样实现起来应该比较优雅,感觉我的设计还是太莽了。

       说这一单元的目的,就是让我们理解什么是契约式编程,只要按照JML的意图实现了代码,正确性就可以得到保障,同时也让我们掌握一定的JML语言的语法格式,能够编写出自己想要的JML规格来给他人使用,这种能力是双向的,不仅要能实现,也能给出架构来,本质上还是对于架构设计的考察,是需要加以思考的。

4.第四单元

       最后一个单元主要就是介绍了UML图,这是一种功能强大的统一建模语言,我们了解的是基础的类图、顺序图以及状态图,我们所要掌握的不仅仅是对各种图中元素的正确认识,同时也要能够利用各种UML图,保证他们的一致性和有效性的同时,来正确地描述代码所实现的功能。

       这一个单元就是要解析三种UML图并且要检查是否出现错误,我采用了类似工厂模式的做法,主解析器里面存储了相关的图信息,然后针对每一个图以及检查错误的需要,分别设立一个类来实现相关的方法,具体操作就是主解析器将所存储的内容分别传入到辅助的解析器中,然后调用相应辅助解析器中的方法,来返回正确的值,具体的数据结构类似于树,也可以按照图来处理,主要的操作无非就是dfs,算法上难度不大,主要就是解析过程比较麻烦,必须要考虑空指针的问题以及搞清楚每个容器的作用,不要张冠李戴,否则肯定会出错误。

       在实验课上我还是感受到了UML功能的强大,的确可以准确地描述程序在执行过程中的各种变化,相较于JML成熟得可不是一星半点,而且还有一定的趣味性和思考难度,是个有趣的统一建模语言。这就告诉我们什么叫做模型化设计思想,针对诸多不同类型的对象构造层次和关系,在构造UML模型的过程中动态维护相关的查询数据,在架构设计当中这是非常有用的。

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

1.第一单元

       由于在整个OO课程当中我都没有掌握自动化生成数据和测评的技术,没有办法,我就只好自己手动构造数据了,其实第一单元手动构造还可以,不算非常难,根据所要求的实现的求导类型进行组合构造数据,比如说大量的嵌套,同时还要注意一些特殊的数据,比如说0和1作为系数和指数啊,自己为难自己一下,造几个数据,其实还是可以测出很多问题来的,利用设置断点,就可以复现问题,定位问题,然后进行相应的修改,同时要正确使用正则表达式来进行格式检查以及项的划分,这些做到的话,应该不会有什么问题。

2.第二单元

       多线程的代码要想进行测试,一是要进行大量的数据,二是要做到精准的投放,此外还要注意一般调试用的断点并不能够检查出来多线程的问题,这就意味着不仅仅要做到自动化生成数据,还要有脚本来支持在某一时刻输入,但是这两者我都做不到。因此,为了检查死锁的问题,我采用了在同一时刻输入大量的数据观察能否正常输出而不卡死,同时辅助以JProfiler来观测进程的执行情况,但其实由于多线程本身执行的不确定性,导致要复现问题其实非常困难,有好多人都遇到了神秘的bug(我被刀的一次竟然还是可以稳定复现的。。。),因此真正要保证代码的正确性,还是要“形式化验证”一波,分析出公共资源,要不要加锁,如何加锁,整个过程以什么方式运行,只有这样,才能在很大程度上避免神秘问题,我就是这么检查的,事实证明保证了逻辑的正确,是可以在强测和互测中生存的。

3.第三单元

       JML这一单元主要利用的工具还是Junit来编写测试代码,其实也就是一个自己手动构造数据的方法,但是与之前的不同,这种方法主要是针对方法的正确性来进行检查的,对不同的方法编写相应的测试代码来检测其实效率比大规模轰炸要好一些,因为可以少做些无用功,而且代码的检查覆盖率比较高,但是这要求编写代码的人对JML规格有着绝对正确的理解,依据规格对不同的情况进行考察,如果理解出现了偏差,那么不仅写出的代码不会正确,做的Junit测试也是基于错误的认知的,那自然也就检测不出来错误,虽然也可以使用JunitNG来自动生成样例,但是由于工具链的不完善以及数据的极端性,导致测试起来不全面,不好用,因此自己构造还是非常有必要的。同时,由于这个单元涉及到算法的考量,对于效率问题也是非常需要注意的,可以构造一些可能耗时非常长的数据来观察是否能够在短时间内完成计算,这一点我就没有注意,使用了时间复杂度超高的算法,导致出现了一些问题。

4.第四单元

       这一单元与UML各种图的结合非常紧密,必须要对UML图有着正确的理解才能够做出来这一单元的作业,虽然指导书上推荐Junit来进行单元测试,可说实话这要是单纯靠自己手写Junit简直要人命,所以我就用staruml画了一些个情况来进行检测,再利用官方包来将mdj文件转化为输入的数据,这样就可以测试了,单元测试是必要的,尤其是最后一次作业,各种错误检查特殊情况都不少,需要一一注意,但是我觉得只要用staruml画出来就可以了,没有什么必要去专门编写Junit,与第三单元作业类似,这一单元也出现了一些涉及到效率的问题,也要构造一些极端的数据测一测,比如说强测里面的菱形继承,就是一个非常好的例子,只要测试做到位,理解到位,这一单元真心问题不大。

四、课程收获

  • 首先那就肯定是掌握了基础的java语言的编写了,在寒假的时候我们完成了预习作业,这时候我真就是个小白,啥啥都不会,连IDE都没弄清楚怎么用(后来发现社区版和高级版还是有一点小区别的),原来还真想咕咕咕了,但是助教说这个算分的,没办法,就只好自己买了相关的书籍,又到网络上去查资料,自己学习,这才做出了作业(结果还是有一个没做出来),做出来了自然就激动,做不出来真就想骂娘,但是正式进入课程还是有惊无险的,这也是java基础做的还可以的原因吧。
  • 其次就是掌握了基础的面向对象的设计思想,包括如何划分类的功能啊,SOLID准则啊,基础的设计模式啊等等,从最基础的继承入手,一步步深入,代码也从最开始的面向过程逐渐地还有点面向对象的样子了,尤其是多线程的时候我觉得是我面向对象的巅峰了,不同类之间的合作从来没这么清楚过,任务完成的也没这么顺利过。
  • 还有就是工程化的设计思想了,OO课程重要的就是迭代设计,每次都有新的需求扩展,如果开始扩展性要是不行后来重构那就是必然了,这一点我深有体会,第一单元次次重构让我一度认为我的OO历程就要在重构中度过了,结果后三个单元还可以,这也说明我有了一点点工程化设计的思想了,也让我认识到了架构的重要性,拿过来任务不要上来就是一顿写,写出了一堆shit你说是忍着呢还是不忍呢,不如先思考一波架构,分析一下需求,即便设计出来的架构也不见得多么精妙吧,但起码思路整理好了,写起来也方便,扩展起来也好办。
  • 当然了也复习了一些基础的图算法知识,这本来应该是数据结构的任务,但当时说实话我学的很夹生(就像夹生饭一样没法吃),当时落下的内容那就只好现在补了,虽然炸了几次算法,但是也让我复习了图的知识,这也是我一直想做但还没来得及做的,也听说了什么tarjan算法和并查集的东西,这个我还是没有做的,都是采用了最基础的图操作,也许暑假的时候我可以搞一搞算法提升自己一波?
  • 另外就是一些辅助工具的使用了,我觉得大家用的最多的还是python去自动测评啥的,但是我还真就不会这个东西,每次作业也就只好“形式化验证”了(瞪眼法的美称),我用的最多的还是Junit,手动构造测试数据,另外就是staruml了,这个东西画起来还是很有意思的,以及多线程观察线程运行情况的JProfiler了,这个东西也给我找到了不少错误之处,死锁的情况还没出现过,至于JML的工具,说实话真心不好用,既然如此,那就不用了,对吧。
  • 最后就是培养了我一定的自学能力,毕竟这个课上的内容有的时候真就不是太能支持作业的完成,指导书要是理解不好也要爆炸的,所以每次作业下来,我第一件事就是阅读指导书,翻来覆去地读,直到基本把所有的要点都理解到位再开始写,然后读助教发的补充材料,学习相关的知识,要是还不理解就要上网了,图有关的知识我都忘了个差不多,dfs和bfs也不会了,那就只好上网学习了,大一看都看不懂的我现在还真就明白了,这也是进步对吧。

       以上就是OO课程带给我的收获了,这些收获可以说都不是单独存在的,做个工程不管怎么说都要考虑到方方面面,这些收获都是综合在一起才能发挥出应有的作用的,我相信OO带给我的进步在未来都可以得到很好的体现,帮助我解决未来的困难与问题。

五、改进建议

  • 希望能够让课程讲授的内容与作业与实验结合更紧密一些,好多次课感觉课上讲的内容对完成作业和实验帮助不大,个人认为课堂上讲的内容有点总结性质,只有一部分的课程有些帮助,比如最开始的继承以及后来的多线程的一部分内容,至于JML和UML的内容,个人认为不听课上的也能完成任务,希望未来可以做出些改变。
  • 希望可以增加实验课的反馈内容,让大家知道自己实验课完成的怎么样,而不是提心吊胆答了一堆最后有可能爆0,只看统计数据个人认为分析不出来什么对自己有用的信息来,这样也可以让人抓住些实验课的特点做出些有针对性的预习和复习工作,像OS实验还能讨论讨论难点所在啥的,能更好地完成实验任务。
  • 希望助教在解答问题的时候尽量不要暗示或者让你自己看着办什么的,我觉得还是有一说一比较好,可能有的问题确实很不值得答,但是既然问出来了那就是当时不知道不理解,这时候来个暗示很有可能不会提供什么有效的帮助,反而让一个提问者更加糊里糊涂,搞不清楚,而且很有可能还加深了错误的认知,我不相信这就是助教解答问题所希望看到的结果,直白的明示是非常必要的(注意不是助教认为的明示,助教可能觉得已经很明示了但在提问者眼里可能是暗示到不能再暗示了,这也应该就是“知识的诅咒”吧),可能有一个地方就一下子没反应过来助教明示一波就通达了,这也能更好地完成任务,希望以后的助教能够改一改这个问题。

六、线上学习oo课程的体会

       这一学期由于疫情的特殊原因,整个OO课程都是在线上完成的,包括所有的线上授课以及线上作业和实验,还是全新的体验,头一次没有面基到老师和助教,感觉还是颇为遗憾的。个人认为在家学习的学习氛围和学习效率都不如在校的时候,这一点OO课程也不例外,其实说实话,听课的时候我并不认真,有的时候真的是听一句漏一句,不过每次上完课我都重新看一遍课件进行再次的理解,并且每次作业都认真完成(虽然有爆炸,但是起码都有效了不是),收获还是非常大的,这也应该是OO课程以实验为主,没有笔试的原因所致。但是线上学习导致我有的时候面临问题的话不能及时和同学探讨,毕竟纯靠网上交流回复起来延迟还是很大的,遇到了困难不能攻克有的时候真的要哭了,我一直认为线上学习常态化就是一句扯淡的话,强调线上学习多么多么好对我来讲是没什么意义的,我还是一个比较老派的人,认为在校学习还是非常必要的。虽然困难重重,但还是走完了OO历程,这个“昆仑课程”我还安然度过没进补给站的,非常感谢老师、助教以及热心的同学的解答,有机会的话还是想和大佬们当面探讨,继续选择OO老师们的后续课程,在有限的大学时间里学到更多吧。OO课程不管怎么说已经过去了,线上学习也教会了我很多东西,期间也有过很多错误的认知,悟已往之不谏,知来者之可追,我的目光也只能开始投向未来,迎接未来的挑战吧。

posted @ 2020-06-14 16:48  DarthVadar  阅读(249)  评论(0编辑  收藏  举报