OO第四单元——UML设计&课程总结
2019-06-23
前言
经历了一个学期的煎熬,OO终于迎来了完结(完结撒花!!!❀❀❀),回想起这几个月的时光真是一段难忘的血泪史(捂脸),当然在磨砺中有所成长,还是很欣慰的一件事情。接下来就先谈谈最后一个单元UML两次作业的架构设计,再总结一下四个单元以来的成长与收获。
UML单元架构设计
第十三次作业:UML类图解析器
- 类图
- 设计策略
本次作业要求实现一个UML类图解析器,难度不算大,但要求实现的方法较为繁杂。
首先需要理清所有UmlElement之间的关系(父子、构成)以及每个元素各自的特征(特有成员变量)。然后是最困难的架构设计,怎样用代码的形式(容器类或自己设计的类)将类图“搭建”成易于处理的形式,以方便各种方法的实现,这就需要用到这一学期以来对OO的所学所想;我的做法应该是很普遍的一种做法,设计了自己的UmlClass、UmlInterface、UmlOperation及UmlAssociation类(提供的其他Uml元素已经够用,直接调用即可),设计每个类的私有成员及方法,要求实现的查询方法大多放在MyClass和MyInterface中实现,稍微提一下输出类实现接口列表的方法(应该是最麻烦的一个方法),需要考虑到类的继承、类的多实现接口、接口的多继承等,最后是用图的BFS遍历解决的;设计好了各种元素,最后剩下的就是在主要的Interation类里把类图“搭建”起来,例如:把attribute相关信息存入MyOperation、associationEnd相关信息存入MyAssociation等等,需要注意的是“搭建”的整体顺序。
第十四次作业:UML顺序图、状态图解析+规则检查
- 类图
- 设计策略
本次作业要求在上一次作业的基础上增加对Uml顺序图、状态图的简单解析,以及三条Uml基础规则检查。
有了上一次作业的基础,这次的顺序图、状态图解析的实现大同小异,而且也没有上次作业那么繁杂(虽然细节方面指导书确实没说清楚),类似地实现了两个用于解析的主类,连同类图的解析器一起放在GeneralInteraction中,实现了完美的三位一体(雾);新增的三条规则检查应该是比较麻烦的地方,我在原先类图解析器的基础上又修修补补了一番,第一条规则略过,第二条规则要求实现对循环继承的检测,出于摸的心态,采取了对每一个类/接口做DFS检测看是否会回到原点的方法(然后就很不幸地在最后一次强测中最后一个点TLE了,当然也有其他实现方面的原因,不过这大概就是摸的代价吧),第三条规则是实现对重复继承(包括实现)接口的检测,还是用的BFS,若是访问到了已访问过的节点则说明重复继承了(不过实际上有点取巧,跟接口的多继承形式和二三两条规则的检查顺序都有关系)。
架构设计及OO方法理解的演进
第一单元:表达式求导
- 本单元主题:JAVA基础与面向对象入门 (正则表达式用法+递归下降)
- 本单元主要完成了从幂函数求导到复杂多项式嵌套求导的演进。
- 架构设计方面,由于是第一次接触较大规模的工程,架构上不是很能看,只是基本做到把各种因子、表达式拆类封装而已,单调且无层次性。当然第三次作业对架构的要求就比较高了(真是次次重构火葬场,架构设计得好的dalao们只需在原有基础上加以些许整改即可,可见架构设计的重要性),为了实现递归下降采用了类似“多叉树”的结构(虽然写得很丑不是很能看 :-)),这大概是在OO课程的学习过程中第一次体会到架构的概念。
- 关于OO方法,初步理解了面向对象的概念,学会了如何提取不同数据类型的特征将其抽象成一个类;在加入不同形式的因子后第一次使用了面向对象“继承和多态”的特性,使得对因子的处理更加简洁规一;不足的是实现中还带有面向过程的思想,把运算处理的方法和数据都糅在一起,这样不是很OO。
第二单元:多线程电梯
- 本单元主题:多线程与线程安全设计(JAVA多线程)
- 本单元主要完成了从傻瓜电梯到捎带电梯再到多电梯智能调度的演进。
- 架构设计方面,相对第一单元还是有些许进步的。三次作业的基本思路都是类似的,调度器消费请求队列、发放任务给电梯,电梯只执行分配给自身的请求,多电梯互不干扰;第三次作业中由于分配任务需考虑的细节增加,选择把调度器进行了分层(主/子调度器),使得一个调度器内的调度逻辑不那么臃肿;然而就是电梯与调度器之间的交互还是做得不足,在调度器内设置静态方法以便电梯线程在运行时调用来分配任务,与原先的构想不符,应该把调度器也设置成线程更为妥当;其次在观摩了同组dalao的代码后,深感自己写的“电梯系统”着实单薄无力,他们实现的一些新增细节类(例如楼层、轨道、IO等),都使得他们构建的系统更为全面、完善且更具功能性。
- 关于OO方法,初步接触了JAVA多线程的编程方法,对于线程安全的把控一定要谨慎谨慎再谨慎;学会了JAVA多线程的几种设计模式,最主要运用的就是生产者-消费者模式,基本上贯穿三次作业,其次还有用到的就是单例模式,将调度器作为一个全局类对电梯进行合理把控;遗憾的是由于时间原因没来得及尝试书中可用的其他设计模式,如发布者-订阅者模式等等。
第三单元:JML规格设计
- 本单元主题:规格化的面向对象设计(数据结构??)
- 本单元主要完成了从路径管理系统到地铁系统的进化 :-)
- 架构设计方面,由于本单元实现的功能都是囊括了上一次作业的全部功能基础上实现的,在保证正确性的情况下可以直接将上一次作业的代码拿来复用,大大降低了重构的程度;其次,由于本单元的主题是规格化设计,规范的JML说明帮助我们对任务的划分、设计的层次性有了更清晰的认识,虽然还有很多不足,但至少尝试了把数据结构以及其上的运算单独开类封装,第三次作业中在许多情况下用到的floyd将其单独开了一个运算类,这样的设计大大减少了代码重复使用的程度,层次划分也相对更清晰;很遗憾的是这个单元还是炸了,但很大程度上是数据结构算法方面的问题(真实还债,抱头痛哭)
- 关于OO方法,学习了JML规格的契约式编程方法,主要是对JML语言有了一定的了解,也体会到了规格化设计的好处(设计与实现分离),虽然这个单元数据结构方面的要求似乎逐渐占据了主导地位 :-);第一次接触了JUnit单元化测试,也试过用JUnitNG自动生成测试样例(可惜只会一些极简单方法测试样例的生成),对测试方面加深了些许理解。
第四单元:UML图解析
- 本单元主题:UML图的理解与解析(架构设计)
- 具体内容在上文中已有所阐述。
- 架构设计方面,这一单元几乎用到了本学期以来所有关于OO的所学所想。虽然实现细节中还有不少地方有改进的空间,但这一单元的架构设计个人总体上还是较为满意的,对于UML图的“搭建”采取怎样的容器类更为合适?自己新定义的类应该怎样实现较为妥当?在思考与实现的过程中我的的确确感受到自己有所长进了,对于类的抽象定义、类与类之间的交互关系、整体的安排设置都有了一定的想法;很可惜,最后一次强测因为TLE炸了一个点(很迷),证明我对时限和算法的理解还存在缺陷。
- 关于OO方法,本单元的主题就是UML各种图的理解和解析。在完成作业的过程中,对各类Uml元素间关系的解读帮助我们加深了对Uml图的理解(类图+顺序图+状态图),对对象内部元素的构成也有了一定的了解;至此,在四个单元循序渐进的磨练中,我们看到了OO编程思想中各个模块的内容,代码和架构方面的能力都得到了很大的提升。
测试理解与实践的演进
- 由于能力不足,以下只是粗浅地阐述下个人的一点想法(纸上谈兵),有许多不足还请见谅。
- 就本学期四个单元以来做测试的经验来看,我更愿意把测试分为两种:
- 定点测试
- 针对各种特殊情况、边界条件进行的测试,通常测试用例及正确输出需要人为编写
- 在刚开始接触OO时用的基础测试方法,互测中自己构造一些具有针对性的数据试图测出别人的bug,事实证明在WF的检测中确实很有效,但是相对的,效率较为低下;再一次接触是在第三单元最后一次作业中,运用的JUnit单元测试实际上也是需要自己构造测试样例和正确输出的一种定点测试,但是通过构造简洁的样例可以判断自己的程序能否正确处理“环路”时的换乘、票价、不满意度等等,更有针对性的发现自己的bug,若是随机测试,测试数据量极大的情况下debug会变得十分困难,因此,我认为定点测试对于最初的bug排查还是很有其实现意义的。
- 随机测试
- 通过数据生成器生成大量高强度随机数据,对多人代码进行对拍查bug的一套自动化程度极高的测试机制
- 第一单元的第二次作业开始,从讨论区获得了Xger的jar包,可以根据正则表达式自动生成随机样例(再也不用自己绞尽脑汁想测试数据了!),测试的效率比起单纯的定点测试大大提升了。后面几个单元就没jar包可以用了,因此数据生成器的实现应该是最困难的部分,这里要很感谢愿意分享自己数据生成器的几位dalao,能够批量生成高强度的随机数据,之后打jar包、命令行进行对拍,能够迅速在短时间内发现bug(当然,一起对拍的人最好还是比较强 :-));接下来是纸上谈兵部分,在和同学交流的过程中(以及围观dalao们博客的过程中),意识到数据生成器也有不同的类型(即针对的方面不同)、实现方面自然也有优劣,比如第三单元作业的生成数据,删除本不存在的路径纯属无效指令,不应大量出现(即增加有效指令的占比);此外也有针对环路生成的数据集(但没见过,其实可能的话还是很想观摩一下相关写法的,现在就纯属纸上谈兵,只会用不会写,很不提倡)
- 小结
- 总之个人感觉是两者都很重要,相互配合能使bug检验以及debug效率达到最高
- 定点测试
课程收获总结
- 首先是最基础的JAVA语法规则,能够写出保证质量的近两千行的JAVA工程代码,码力确实有了很大的提升
- 其次是关于面向对象的思想与程序设计,逐渐摆脱大一时面向过程的思想,每次写代码之前第一步是考虑清楚如何设计对象、对象间如何进行信息的 交互,对面向对象语言的多种特性:抽象、封装、继承、多态有了深入的了解
- 关于学习的具体内容,学会了多线程与线程安全的程序设计,接触了JML规格并体验了契约式编程,深入了解了UML的多种图,当然学得还不够深,希望将来有机会还能更进一步地学习
- 架构设计能力的提升,不同于大一时学习的C语言,OO促使我们去写一个工程,而不是一个流程;一个好的工程,必然需要可靠的架构去支撑,这就需要我们在每次作业中不断地去思考如何设计一个完善的架构,最好易于维护且具有良好的可扩展性(虽然最终我也没能达到这个地步,但还是收获了很多)
- 学会了一些基本的测试方法,对开发中代码测试的流程有了一定的了解。遗憾的是没能凭借一己之力完成一套完整的评测机制,这里要严肃批评自己的能力与惰性
- 增强了深夜爆肝的能力?比如现在(雾)
具体改进建议
- 关于指导书内容
- 这里仅针对第四单元,前三个单元指导书的描述还是较为简洁清晰的,但是最后一单元(尤其是最后一次)细节方面就描述得不太清楚,从讨论区大家提问讨论的活跃度也可见一斑(比如,状态图的起始状态与终止状态、不同transition的区分标准等等),在指导书中没有明确的说明,导致大家各种胡乱猜测 :-)。还有就是最后一次的指导书给的样例显然不够充分,似乎只给了顺序图的?还没有标准输出……希望能改进一下,样例还是要给的,并且尽量覆盖面大一些吧……
- 关于中测
- 难度方面,建议适度提升中测的难度,帮助大家更全面地发现自己的bug。之前有过轻松过了中测结果被强测锤爆的惨痛经历,当然这跟自己测试的不充分也有很大关系(或许也是课程组的本来目的,出于锻炼大家测试方面的能力),但可能的话还是希望能适度提升一下难度,毕竟不是每个同学都能做出一套完整的高强度测试机制的TAT;数据方面,主要针对第一单元第三次求导作业吧,当时其实因为考虑不周漏过了非常致命的bug,然而强测数据神必地完美避开了我的bug,或许数据应该出的更有针对性一些(比如说,考虑三角函数括号内嵌套负数的情况等等,然而在强测数据中并没有体现)。
- 关于实验课安排
- 也是很多同学觉得不妥的地方,很多时候都是上午刚上完课下午就做相关内容的实验了,没有足够的时间去实践、理解、消化,直接上手的话通常会败得很惨(最惨的应该是“继承与多态”那次)。建议调整一下实验课与理论课的时间间距,或者,像JML单元那次一样提前告知大家需要预习哪些方面的内容也是不错的选择,有所准备至少不会被打得措手不及。
- 待补充……(想到再说)
最后的最后
最后在这里还是要很诚恳地感谢一学期以来老师和助教们的辛勤付出!其实本来在还没上OO课程前内心充满了恐惧,一方面是因为自己太弱,另一方面是听到的各种神秘传闻(据往年的说法这是一门比计组还魔鬼的课程,瑟瑟发抖)但实际的一学期接触下来,虽然有遇到过困难的时候,但并没有想象中的那么可怕,费一番功夫最终还是得到了解决。所以真的很感谢今年助教老师们对OO进行的改革!即便是这么菜鸡的我,也做到了坚持走到最后,从先前最多写过两三百行代码到最后一千八百行的工程代码,这个过程中的成长和收获是非常宝贵的。
还有特别要感谢的朋友,写这篇总结博客时渐渐回想起了很多事情,我真的是在他人的无私帮助下一步一步走来的呀,在这里要表达一下最真挚的谢意:真的是、非常感谢!!
祝愿大家一切顺利!OO完结撒花!!❀❀❀