OOP第三次作业

第三单元博客作业

• (1)梳理JML语言的理论基础、应用工具链情况
  • JML语言理论基础

    Java建模语言(Java Modeling Language,JML)是一种进行详细设计的符号语言,他鼓励你用一种全新的方式来看待Java的类和方法。JML是一种行为接口规格语言 (Behavior Interface Specification Language,BISL),基于Larch方法构建。BISL提供了对方法和类型的规格定义手段。所谓接口即一个方法或类型外部可见的内容。通过在Java代码中增加了一些符号,这些符号用来标识一个方法是干什么的,却并不关心它的实现。使用JML,我们就能够描述一个方法的预期的功能而不管他如何实现。通过这种方式,JML把过程性的思考延迟到方法设计中,从而扩展了面向对象设计的这个原则。

  • JML应用工具链

    • 常见的有openjml,以及SMT Solver来进行规格的静态检查

    • openJML-check参数可以对规格进行检查(不对程序内容进行检查,单纯检查规格正确性)

    • openjml-esc参数可以对规格进行检查,同时指定SMT sovler对程序的具体实现进行静态检查

    • openjml-rac参数可以生成断言对程序进行运行时检查

• (2)【改为选做,能较为完善地完成的将酌情加分】部署SMT Solver,至少选择3个主要方法来尝试进行验证,报告结果
• 有可能要补充JML规格
• (3)部署JMLUnitNG/JMLUnit,针对Graph接口的实现自动生成测试用例(简单方法即可,如果依然存在困难的话尽力而为即可,具体见更新通告帖), 并结合规格对生成的测试用例和数据进行简要分析
JMLUnitNG

  • 对于实现两个数相加的方法进行测试

  • 使用jmlunitng.jar生成测试文件

  • 编译相关文件并进行测试

  

从上图可以看到有两次自动测试是失败的,通过观察数据我们发现是由于加法的溢出导致的(忽略这些5

 


JMLUnit

在三次作业中,我都使用了JMLUnit来对我的方法进行断言检查,由于是单元测试,非常容易定位错误,是非常好用的,也检查出了几个bug,并且在进行我的代码重构时,也能使用它检测我的代码是否能支持之前的功能(

下面是部分代码截图

 

• (4)按照作业梳理自己的架构设计,并特别分析迭代中对架构的重构

第一次作业类图如下:

  主要采用双HashMap来存储pathPathId的映射关系,并且在容器中添加或删除时维护一个存储点出现次数的HashMap来更新不同的点的个数,就不可能TLE了,并且使用Junit自己对于所有方法编写相应的极端测试样例


第二次作业的类图如下:

  由于出现了图的结构,为了更加方便图的计算,我新增了一个表示图的关系和计算的类GraphCal来处理有关于图的问题。但是有一个地方没有处理好,出于对于评测机时间的不确定性,我将上一次作业的Mycontianer的内容复制了过来,并且更改了其中的数据结构,以求计算时间的缩短,这样是很危险的,对于以前的代码,最好的做法就是遵循开闭原则。在图的关系的存储上,我采用了邻接矩阵(为了方便),由于边的无权的特性,选择了BFS进行计算,在图不变更的前提下,会调用之前的计算结果(在求得a到b的最短路径时,这条路径上的所有点之间的最短路径也是此路径),并且使用Junit自己对于所有方法编写相应的极端测试样例


第三次作业类图如下

从类图来看,显然我的类是很臃肿的,类之间的职责并不均衡,GrapgCal的方法数量明显过多。在这次作业中,虽然CPU时间明显延长,并且允许的最多不相同点数也减少了,但还是害怕爆零(结果跑出来最长的也只有4s左右,匿名感谢wjy),而且有之前的Junit的支持,将第二次的代码原封不动的copy过来,并对数据结构进行优化,也就造成了类的职责不均衡以及高耦合的情况的发生,这次是自己的着重点放错了(分奴),以后还是要好好遵守开闭原则,不对源代码进行修改,以免产生bug

这次我采用的方法是wjyfloyd算法,我将每条路径每个点之间的最短距离存在一个二维堆数组中,堆中的对象是我构建的Edge,存放长度以及其所在的路径ID,并重写了比较器,每次变更图结构时,维护这一二维数组中的堆,取一条路径上两点间的最短路径时,只需要取对应的堆顶元素即可,剩下就根据不同要求生成对应的初始数组,使用floyd算法进行计算

• (5)按照作业分析代码实现的bug和修复情况
  • 在公测以及互测中没有出现bug

• (6)阐述对规格撰写和理解上的心得体会
  • 规格撰写的心得体会

    规格的撰写是一个非常重要的步骤,一定一定要与实现隔离,不能束缚代码的具体实现,撰写者需要关心的是代码的数据形式以及其变化,用JML语法表现出这些变化,并且需要注意前置条件以及后置条件的完整性,要涵盖这一方法的所有信息。在继承一个父类后,还需要注意子类的规格要满足父类的规格,子类重写父类的方法时前置条件要放宽,后置条件要收紧,保证父类和子类规格的一致性

  • 规格理解的心得体会

    最大的体会的就是理解规格时要注重这一方法所要实现的目的,要达到怎样的效果,想清楚所有的规格之后,再去考虑代码的实现,并且最好考虑在此基础上的扩展性,构建一个较好的、易于扩展的框架

posted @ 2019-05-22 09:40  Puddingg  阅读(154)  评论(0编辑  收藏  举报