第四单元的作业是关于UML图分析的作业,实现的功能包括对于三种UML图的分析以及对于输入的json内容错误查询,总体难度不大。主要的考察点在于对于数据分析的方法和对于某些数据结构(例如树和图)的应用。总的来说,本次作业的难度和上次难度差不多,但也要注意细节的把握。
统一建模语言(Unified Modeling Language,UML)是一种为面向对象系统的产品进行说明、可视化和编制文档的一种标准语言,是非专利的第三代建模和规约语言。UML是面向对象设计的建模工具,独立于任何具体程序设计语言。
对于类图,UML将类(class)、接口(interface)、方法操作(operation)、属性(attribute)等都视为对象元素(UMLelement),UMLModel容器管理着模型的所有元素。其中:
UMLClass 对应用户所构造的类
UMLInterface 对应用户构造的接口
UMLAttribute 对应用户构造的类的属性
UMLAssociation 对应用户构造类之间的关联性(一般拥有两个end,对应两个类中的内容)
UMLAssociationEnd 对应用户构造类互相关联性(0..1 表示可以有0个或者1个实例,*表示对实例的数目没有限制,1 表示只能有一个实例,1..* 表示至少有一个实例)
UMLGeneralization 对应用户构造类的泛化/继承
UMLInterfaceRealization 对应用户构造接口的实现
UMLOperation 对应用户构造类的方法操作
UMLParameter 对应用户构造类的方法操作的参数
具体的树形结构如图所示:
此外,各个元素的通常成员有_parentId(父id,类似指针), _id, _type(是否reference), name, type, visibility, direction, source(源类), target(目标类), reference(相关的两个类,正常情况分两个end元素), navigable(关联方向)等等,会在对应元素的内容中展现出来。
类之间存在六大关系:
泛化/继承(Generalization),Java单继承,UML可以多继承
接口实现(InterfaceRealization)
关联(Association)是一种拥有的关系,它使一个类知道另一个类的属性和方法
组合(Composition)是整体与部分的关系,但部分不能离开整体而单独存在
聚合(Aggregation)是整体与部分的关系,且部分可以离开整体而单独存在{none, shared, composite}
依赖(Dependency)表示一个类A依赖于另外一个类B的定义
它们在图像上反映为不同类型的连接线,具体可以在StarUML中查看。
顺序图中存在UMLCollaboration,内包含:
Role 交互对象
UMLInteraction 交互行为
UMLLifeline 生命线
UMLMessage 消息传递
UMLEndPoint 顺序图终结点
其中,每个生命线应该对应上层中的一个对象,Message分为四类,以上都可以在StarUML中打开相应的mdj文件看到。
状态图中存在UMLStateMachine,其中包括:
UMLRegion 状态图范围,包括状态和转移信息(顶层)
UMLState 在UMLRegion下一个层次
UMLPseudostate 初始状态,获取kind可得到initial标志
UMLFinalState 结束状态
UMLTransition 和UMLState同一个层次,是状态的转移(包含guard)
UMLEvent 转移的响应事件(一般是Transition下的trigger)
UMLOpeaqueBehaviour 状态转移的结果
UML001:类图元素名字不能为空
UML002 :不能含有重名的成员。**针对类图中的类(UMLClass),其成员属性(UMLAttribute)和关联对端所连接的UMLAssociationEnd不能有重名
UML007:不能有重复继承
UML008:不能有循环继承
UML009:不能有重复实现
UML011:接口所有属性均需要为public
UML021&022:初状态最多只有一个迁出,且它不能有trigger和guard
由于三次作业层层递进,每次作业的架构均包含在了后一次作业的架构中,因此我直接以最后一次作业的类图进行说明。
第一次作业是对于UML类图的分析,同时也是为以后的作业打好了框架。
在架构设计上,我首先将传入的UMLelement按类别分别存入相应的Map或Set中,在将所有内容读取完成后,通过遍历这所有的Map和Set,建立一个层次分明的树林,用于对后面功能实现的查询。为了减少时间复杂度,对于每个树杈节点,我均使用两个Map(分别以id和name作为键)来存储,从而减少了遍历,为了检测重名问题,我又使用一个<name, number>的Map来存储每个名字出现的次数,避免了遍历检测重名问题的时间。对于下层仍有元素的内容,建立一个自己的类,在类中使用Map或Set存储下层元素即可。
在具体功能实现上,对于各个信息的查询实际上就是对于建好的树中内容的操作,只需要简单利用数据结构学到的算法就可以轻松解决了。
第二次作业新加入了对于UML顺序图和UML状态图的操作,具体的实现和第一次作业的方式完全一致。
在架构设计上,将这两类图也建成相应的两片树林,而后对数据结构进行操作即可。本次需要实现的需求极其简单,甚至不需要数据结构算法,是三次作业中最为简单的一次。
对于性能问题,仍然采用用空间换取时间的方法,建立更多的Map来减少可能的遍历,比如对于UMLStateMachine,UMLInteraction均建立如第一次作业所说的单独的类,并使用三个Map进行存储。
第三次作业是对于之前输入内容合法性的判断,需要判断的内容在第一部分已经进行了解释,在此不再赘述。
在这些检测中,真正需要思考的是对于循环继承和重复继承的检测方法,其它的检测都比较简单,在对应的读取位置判断以下即可。对于继承和实现问题,因为我们保存了输入的InterfaceRealization和Generalization,这些就相当于是图的边,而输入的各个元素则是图中的节点,于是这一问题就转变为了对于图中环路和多条路径的查找。
第一次作业的bug比较无脑,因为我使用了HashMap来存储参数的类型,因此参数类型重复的参数会被过滤掉,导致查询方法的参数是会出现缺少的情况。由于充分考虑了时间复杂度,因此并未出现TLE。
第二次作业一遍通过,未发现bug。
第一单元是面向对象设计的初步,属于从面向过程到面向对象的过度阶段,代码主要是按照求导的要求机械的按顺序编写,没有为需要的容器创建新的类,只针对表达式、因子、求导之类的要素建立了相关的类。
第二单元是面向对象的延伸,针对于每个数据结构都有对应的类,对于输入输出和线程管理也建立了相关的类,在本单元中逐步开始进行采用抽象的方法,将功能和对应的模块相适应。
第三单元是JML设计单元,在本单元中,主要是对于JML语言的理解和根据JML书写代码。我们根据官方接口,实现自己的容器,用于用户查询等操作。在架构设计上,还增加了缓存计算层,将数据层与应用层独立开来,以实现对于时间复杂度的优化。
第四单元和第三单元有一定的类似之处,需要按照要求书写相关的方法,实现对于数据的分析和处理,但具体的实现要求不再向第三单元一样机械,而是需要自己理解要求进行编写。
在第一第二单元中,对于测试的理解仍然停留在整体的测试之中,第一单元只需要手写评测机,第二单元则同时考虑了线程问题,使用Jprofiler对于线程的状态进行有效的分析,总体而言仍然处于输入和输出对拍比较的阶段。
从第三单元开始,由于代码要求实现变为多个离散的方法,因此,对于代码的一部分,特别是增量开发的部分进行单独的测试成为了测试的重点。本两个单元的正确性测试由于方法的离散而变得比较简单,但是TLE的风险空前加大,主要的精力都放在了优化时间复杂度上。
首先,通过课程,我学会了java语言程序的编写,了解了面向对象思想的基本原理和具体要求。虽然压力比较大(一次作业只有三天时间,而且还有OS的干扰),但是在巨大的压力中获得的收益也比较大。可以说,仅仅短短的一学期,我在代码能力上,在代码风格上都获得了很大的提高。
其次,个人的思维能力得到了一定提高。因为本人并不是信息竞赛生,因此,虽然大一学习了许多数据结构和算法,但是仅仅靠课程的训练完全没法掌握,在本课程中,在学习面向对象的同时也巩固了之前学习的算法和数据结构知识,开阔了个人编写代码的思维能力。
最后,课程也锻炼了我寻找bug,开发测试点以及编写评测机的能力,这些能力作为编写代码的附加产品,也成为了我在本课程中的收获之一。
本人对于本课程说实话满意度挺高,除了感觉互测和紧张的时间非常折磨人,个人认为这是CO-OO-OS体系中最为良心的课程了。
个人建议:
希望可以延缓一点时间吧,每周只有三天的测试时间的确有点少了,希望可以在星期三同步开始测试,缓解周末的压力。
希望指导书可以详细一些,尽量排除一些歧义。。。。。。。已经出现过多次理解问题了。
希望理论课也可以讲一些相对具体一点的讲解,毕竟全思想的讲解对于一部分人比较难以接受。