BUAA-OO Unit4 UML系列
本单元要求实现一个UML分析器,解析mdj文件数据,对UML类图、顺序图和状态图进行分析,通过输入指令来进行UML图中有关信息的查询。同时对模型进行有效性检查,如果模型不符合UML规则,抛出异常。
1 总结本单元作业的架构设计
本次作业程序主干逻辑的架构已经非常清晰,采用了层次化设计的方式。在完成接口时,只需要在UmlElement的基础上实现自己的各个UmlElement类,储存后续指令需要查询的信息和实现方法。
第一次作业
第一次作业是实现类图解析器。

其中,MyUmlInterface、MyUmlOperation、MyUmlClass是根据对应Umlxxx类实现的类,其余Uml类由于在本次作业中没有额外储存属性的需求,因此直接使用官方包中的类即可。
下面以MyUmlClass为例:
-
MyUmlClass-
Umlclass umlclass储存对应的Umlclass类 -
MyUmlClass parent储存父类 -
ArrayList<UmlAttribute> attributes储存属性 -
ArrayList<MyOperation> operations储存方法 -
ArrayList<MyUmlInterface> interfaces储存接口 -
ArrayList<MyUmlClass> associations储存关联类
-
在UmlLibrary类中,有HashMap<String, MyUmlClass> classList储存所有类和类对应的id。构造函数对UmlElement[] elements进行分析,当type属于UML_CLASS时,将该类加入classList中;当type属于UML_OPERATION时,根据parentId寻找到对应的MyUmlClass,并将方法添加进MyUmlClass的容器中。对所有元素进行类似的处理,即可构建起完整的架构,即:

需要注意的是,因为输入并非按序,有可能方法在类之前出现,因此需要多次遍历。
第二次作业
第二次作业在前一次作业的基础上增加了顺序图和状态图。

时序图主要操作是对生命线之间消息的计数,状态图除了计数方法以外,还要求实现getTransitionTrigger,列出触发从一个状态转移到另一个状态的事件列表,需要存储event和transition之间的关系。
整体架构如下:

第三次作业
第三次作业在第二次作业的基础上增加了模型有效性检查。

建立了有效性检查类UmlCheck,实现官方包UmlStandardPrecheck接口。整体架构上基本和上一次作业相同,其中Uml002检测循环继承,在处理接口循环继承时,由于一个接口可以继承多个接口,需要使用dfs找出循环继承链。为了确保所有循环继承链中的接口均被计算到,我遍历了所有不在set内的接口,搜索以其开始并以其结束的路径,并将路径内的接口加入set。
2 OO课程总结
总结自己在四个单元中架构设计及OO方法理解的演进
在学习OO课程前,我没有任何面向对象的基础,写过的代码都是完全面向过程的代码。经过一个学期(困难的)学习,我认为我学到的面向对象并不完全是继承、多态、封装这些“面向对象的基本特征”的实现,而是一种抽象的思想:选取事物的关键特质作为属性,将事物抽象化为类,将属性和方法组织在类中;将事物之间的关系抽象化为类之间的关系。通过面向对象的编程,能够将一个复杂的系统化整为零、拆分层次,将整体的操作分割为局部的方法。当然,直到现在我也还没有能够很好地理解和运用面向对象的思想,但在开始动手写代码之前,我会留出一些时间去思考如何面向对象地设计架构,实际操作时再根据现实需要做一些修改。总体而言,除了第一单元之外,其他单元都没有出现重构的现象。
第一单元
第一单元多项式求导,在第一次作业中,我对于面向对象基本没有多少了解,只采用了正则匹配的方法简单地写了两个类,并且还习惯将很多操作放在同一个方法里,以及大量的if-else结构,现在看起来这些代码十分令人痛苦。后面的两次作业采用了递归下降的方法,第一次尝试使用继承,进行多项式->项->表达式因子的逐步转化,然后再根据表达式因子的种类进行求导。

第二单元
第二单元目的选层电梯,重点是学习多线程,通过对共享数据上锁确保线程安全。这个单元开始有意识地去设计一些架构,参考了课上实验的设计,采用了输入、调度、执行分离的架构,输入线程将乘客送入等待队列,调度器对乘客进行分配,将乘客分配到处理队列当中;每个电梯对应一个处理队列。等待队列和处理队列与两个线程相联系,线程不能同时访问共享数据。

第三单元
第三单元JML规格,这个单元不要求自己进行架构的设计,而是需要严格地按照JML规格实现方法。实现本身并不难,但由于评测机对时间复杂度有要求,在数据结构的选择上需要多做一些考虑,对于需要进行大量查找的数据结构不能简单地使用容器。同时还学习了一些算法,例如并查集、Dijkstra算法的堆优化等。
第四单元
第四单元UML系列,这个单元将层次化体现得很明显,从交互类到类图,到类,到属性和方法,再到参数,从上到下逐次调用。在实现的时候我为了方便直接将顺序图和状态图存储在了原先的类图构造里,其实不是很合适,类图、状态图和顺序图之间应当做到低耦合。
总结自己在四个单元中测试理解与实践的演进
在第一单元时,由于时间紧张,只使用了手动构造数据的形式测试了一些极端多项式。第三单元开始尝试使用一些数据生成程序和与同学代码自动比对&计时的程序来进行测试。我使用的程序是完全随机地生成数据,在研讨课上曾经听到过同学使用函数构造极端数据的方法,显然比随机生成数据效率高。但这样进行黑箱测试并不能完全保证程序正确。在第三单元中,学习了Junit的一些使用方法,通过判断每个方法的执行结果是否和预期一致来确保方法的正确;如果每个方法都准确无误,程序的结果自然也不会出错。
总结自己的课程收获
经过一个学期的学习,基本能够了解JAVA面向对象并利用JAVA进行一些较为简单的开发;了解了多线程、UML图等知识;理解了规格对于开发的意义,并能够根据给出的规格实现方法;能够比较熟练地使用git进行版本控制;尝试了随机生成数据和对拍测试、Junit测试等测试方法。
作为编程苦手,在研讨课大佬们的分享中也收益良多,非常感谢在讨论区、水群和研讨课上愿意分享自己思路和知识的同学们。
对我而言,OO课的课程设置还是强度比较大的,因为其他课程和工作的缘故,基本上每次作业只有三天左右的时间,在这些时间里要去学习作业需要应用到的新内容,设计架构,完成实现和测试,时间很紧张,大部分周末都是面对着IDEA度过。但即便是对于我这种并不擅长编程的同学,仅仅是跟上OO课进度这件事,就已经能够带来许多收获了。更夸张地说,可以说OO课重新塑造了我的编程思维,让我在编程时第一次地把抽象、层次、架构这些概念应用在实践中。
当然,收获更多,也会意识到差距更大,未来继续努力。
立足于自己的体会给课程提三个具体改进建议
-
对于作业的时间限制:个人希望每次作业的发布时间可以提前一些,适当缩短互测时间,或者互测、bug修复与作业发布同时进行,这样可以留出更多的时间来学习新内容和设计架构。每个单元的第一次作业任务量都比较大,要去了解本单元需要用到的新内容,还要设计架构,周三晚上发布,周四一天满课,剩下周五周六周日三天的时间会比较紧张。或者提前一周在博客周发布一些下单元内容的预告,让大家提前了解相关内容,做一些思考,也会让第一次作业轻松一些。
-
对于作业安排:建议对第一单元的作业做一些改进。对于没有基础的同学而言,即便是做了pre,在第一单元作业面前也会感到有些不知所措;特别是第一次作业可以使用正则表达式完成,但由于JAVA正则表达式不支持递归,第二次作业必须要更改架构。希望这个单元指导书上能够增加一点点提示,这样就可以让同学们少走很多弯路。
-

浙公网安备 33010602011771号