OO第三单元总结
- OO第三单元总结
- 一、JML理论基础、应用工具链情况
- JML理论基础
- JML应用工具链情况
- 二、部署JMLUnitNG
- 三、架构设计
- 工程结构
- 算法设计
- 三、出现的BUG以及测试方式
- 我出现的BUG
- 我hack到BUG
- 测试方式
- 一、JML理论基础、应用工具链情况
- 四、心得体会
一、JML理论基础、应用工具链情况
JML理论基础
我所理解的JML规格化设计语言,是设计契约的一种表达形式。应用JML表达对代码的需求,避免了自然语言不严谨的问题,可以一定程度上降低因为沟通问题而出现的代码出错的概率。
我们在主要使用了JML中的方法规格和类型规格,用JML的表达式规则来表达。
方法规格是规定方法的行为的规格,规定了这个方法在某种前置条件下,执行完方法之后应该满足什么后置条件。方法规格同时也限定了这个方法执行的副作用,也就是对对象属性或静态变量产生的影响。JML方法规格也针对java语言抛出异常的特性,规定了方法在什么条件下可以抛出什么异常。规定了执行完方法之后满足的后置条件,执行方法过程中产生的副作用以及抛出指定异常的条件,就可以基本唯一确定一个方法的行为了。
类型规格我们在这次作业中用的不多,类型规格主要是限制了类属性的变化。不变式invariant规定在所有可见状态下都要满足的特性,如 invariant seq_nodes != null
;状态变化约束constraint约束了变量变化的形式,如//@ constraint counter == \old(counter)+1;
有了类型规格约束,就不需要在每个方法的方法规格里面都用ensures语句对成员变量进行约束了。
JML应用工具链情况
主要使用了以下工具:
-
OpenJML:用于验证JML的工具,可检查JML语法的规范性,也可以验证Java程序是否符合规格。
-
JMLUnitNG:可用于自动生成数据检测程序。
二、部署JMLUnitNG
使用JMLUnitNG的过程中不知道出现了什么问题,其它同学Fail的第一个点我Pass了,然后Group的Constructor测试Fail了,其它依赖Constructor的方法就Skip了...
反复尝试之后也没有找到原因,遂放弃。
看起来JMLUnitNG的测试逻辑是使用极端数据,先用极端数据构造对象,然后用极端数据构造出来的对象进行其它测试。
三、架构设计
工程结构
第九,十次作业均是直接按照JML的规格一个方法一个方法实现的,没有特殊的架构设计。
第十一次作业中,由于加入了Dijkstra,并查集,点双连通分量算法的实现,我将算法实现部分单独分出了一个包:
在其他地方使用相应算法的时候,直接调用相应类中的方法即可。
算法设计
在第十一次作业中,queryMinPath我采用堆优化的Dijkstra算法实现,堆优化的实现方式是借助java中优先队列(PriorityQueue)容器来实现的。
queryBlockSum与isCircle我是采用并查集算法实现的,在NetWork类中直接维护一个并查集成员变量,每次person之间关系发生改变或者查询person之间关系的时候都更新这个并查集。由于并查集适用于更新后多次查询,而且没有删除关系的情况,所以并查集很适合用于这次作业的算法实现。
QueryStrongLinked我是采用标程一样的做法,即两重BFS通过每次删去一个点判断是否联通的方式判断是否为点双连通。
三、出现的BUG以及测试方式
我出现的BUG
我在第十次作业中由于对@requires前置条件的理解不正确,导致出现了group人数大于1111情况下输出错误。修复方法就是在addToGroup()中增加判断,人数大于等于1111的时候不进行任何操作。
第是一次作业中我出现了queryStrongLinked超时的情况。超时的出现原因是BFS遍历过程中,标记使用不当,导致已经遍历到的点在某些情况下会被重新遍历。强测中没有发现这个bug,有好几个数据点都是以1.8s/2s , 1.9s/2s的时间勉强通过强测,但是在互测中遭到了无情轰炸。
我hack到BUG
这个单元的互测主要靠的是读代码,然后构造有针对性地数据集来hack。因为本次作业中大家的大体结构都相同,都是按照JML严格实现的,功能上可能不会出现大问题,导致使用随机数据hack的效率不高,所以只能通过读代码的方式针对性hack。
通过读代码,我在第九次作业中发现了没有缓存导致的超时BUG,第十一次作业中其他同学queryStrongLinked, queryMinPath超时的BUG。
测试方式
通过随机构造数据集的方式,和小伙伴进行对拍测试。读自己的代码并不能发现多少问题,但是写能判断正误的评测机又相当于把这次作业用python重写一遍,所以采用对拍测试的方式。对拍测试很有效,成功在提交之前发现了很多BUG,比如deletePerson()忘记写的BUG。
四、心得体会
通过JML,我在这个单元中接触到了契约式编程的思想以及借助JML的实现方式。这个单元的任务量相比前两个单元有所减少(主要是思考量,因为不用在架构上花很大心思),但是仍然很容易出现错误,需要细心编写程序并且耐心进行测试。虽然我们这个单元是按照课程组提供的JML规格严格实现,但是有人为我们提供规格 != 我们不需要思考,事实证明如果不对设计架构以及要实现的方法在整个工程的作用进行仔细思考,即使按照规格书写代码仍然会发生问题。我个人认为JML可能用处不大,但是在这个单元学到的编程思想仍然是很重要的。