JML 规格设计分析

一、设计分析

1. 路径容器的规格设计

  • 第一次作业需要实现一个路径管理系统,可以通过输入各种指令来进行数据的增删改查等操作。同时这一单元的三次作业中,都没有性能分的要求,有的只是受限制的 CPU 时间,这一次作业的 CPU 时间是 10 秒以内,又因为第一次作业设计的部分很少,所以只要不玩的太脱,几乎不会超时,换句话说,第一次作业几乎是人人满分。
  • 我的程序架构中,使用了 ArrayList 作为 Path 类的存储结构,包含一条路径中的结点;使用三个 HashMap 作为 PathContainer 的存储结构,前两个分别是 pathid -> path 和 path -> pathid 的 HashMap,最后一个 HashMap 用于计算容器中每个点存在的次数,方便了 DISTINCT_NODE_COUNT 方法的计算,直接返回这个 HashMap 的 size 即可。
  • 下面是第一次作业程序的 UML 类图:

  • 从 UML 图可以看出我仿照着 Path.java 和 PathContainer.java 实现这两个类中的方法。
  • Method 复杂度分析:

  • Class 复杂度分析:

  • 这两者的复杂度都控制得比较正常。

2. 图的规格设计

  • 第二次 JML 的作业也不算很难,只是我觉得有点偏向数据结构的知识了,需要实现一个图的管理,图中包含路径,路径包含点。需要实现的方法中,最复杂的是找两个点之间的最短路径;这次作业限制的 CPU 时间为 20 s,这就比较严格地限制了我们不能在每次求最短路径时重新算整个路径,要不然很容易超时。
  • 我第二次作业的程序架构,Graph 类包括了上次容器类的方法,然后另外建立了一个 HashMap 存储每个点的领结点,然后在需要求最短路径时再通过 Dijkstra 算法算得每个点与其他点的最短路径,并储存在上述 HashMap 中,这个设计是因为在我们的指令中,图结构变更仅有很少的 20 条,但是取最短路径的指令可以有 7000 条之多,所以,存储每次获取的最短路径,可以有效解决每次求最短路径都需要用 Dijkstra 算法检索一遍的问题,而可以直接在 HashMap 中搜索相关数据即可。
  • 以下是第二次作业的 UML 类图:

  • 和上次一样,使用了官方给的 Graph.java 并将容器类的方法添加在其中。
  • Method 复杂度分析(只截取了复杂度较高的方法):

  • Class 复杂度分析:

  • 从第二次作业开始,路径间互动的算法复杂度变高了起来。

3. 地铁系统的规格设计

  • 最后一次 JML 作业需要实现一个地铁系统,新加入了票价、换乘、不满意度的概念,这导致了我们这次的作业复杂度成指数倍地增加,因为每一种计数方式都需要遍历所有的路线,并找到最小值,但是这次的 CPU 时间给的比较宽松—— 35 s,这次给了我们足够的想象空间,去构建我们想完成的数据结构。
  • 第三次作业,我的想法是每个有多条路径通过的点来构造一个根点来连接其他所有的真实的点,再把这些真实的点当作伪点来连接当前路径中它要连接的点,说白了就是一个复杂的拆点,只不过这样可以大大减少我构造的图中的边的数量,从而大大减少 Dijkstra 从优先队列中取出最短路径的次数,缩短程序运行时间。
  • 在构造完我所说的跟点的 HashMap 后,就可以将三种不同的算法各自构造一个 HashMap 作为点的边权来进行 Dijkstra 的计算,然后和上次作业一样把边权存储起来方便下次调用。
  • 还有一个特殊的指令是获取地铁系统中所以连通块的数量,这个指令我是通过把容器中每一条路径的第一个点取出来,判断它们是否相连。
  • 下面是最后一次 JML 作业的 UML 类图:

  • 因为内部的方法比较复杂,我就不打开 method 展示了。
  • Method 方法复杂度:

  • Class 方法复杂度:

  • 这次的复杂度比上次大大增加了,因为我在每次图结构变化的时候,都需要重构我的四个 HashMap ,所以相当于 50 次左右的重构图结构;相应的,获取四种最短的方法调用次数也有所增加。

二、Bug 分析

  • 遗憾的是,这三次作业中,我都没有在互测中找到别人的 bug,我找 bug 的方式是利用输入相同的数据,然后判断两位同学的输出是否相同,来找出它们的错误,可惜的是三次互测中我给每组同学运行了上千组随机数据,他们都没有出现一例错误,可能这是因为 A 组大佬们太强了吧(得益于这个单元没有性能分,三次作业我在强测中都是满分)。
  • 那下面我就来说说我自己程序在编写过程中遇到的 Bug ,或是超时问题:
    • 第一次我求最短路径时,每次调用两个点间的最短路径,我会遍历全部的点求得整个图的边权,后来我改进为只求当时那个点的边权,这样在图结构发生变化时,有效减少程序运行时间;
    • 第一次作业中的容器类,我原本用的是 ArrayList 存储 Path,但后来我发现这样用 pathid 来搜索 path 时,速度明显变慢,因为 ArrayList 本质上是一个数组结构,搜索时需要一个个按照索引来搜索,比 HashMap 通过 key-value 来搜索要慢的很多,所以后来我采用 HashMap 来存储。

三、JML 理论基础和工具链

  • 这一单元我们的编程需求完完全全来自于 JML,所以 JML 知识的掌握对我们来说尤为重要;
  • JML 又名 Java 建模语言,用于制定 Java 模块的行为,但是它又不需要完全精确到代码细节的实现,而是对某一个模块的行为进行规范;
  • 一个正常的 JML 可以包含下面几个部分:前置条件、后置条件、会改变的元素和属性、不会改变的元素和属性、不正常的行为发生时抛出异常;这些具体实现的表达式也已经在我们的指导书中详细地介绍了,我在这里也简单梳理一下:
    • JML 中常用的表达式:

      • \old(expr) 表达式用来表示一个表达式 expr 在相应方法执行前的取值;
      • \result 表达式表示方法的执行返回结果;
      • \forall 表达式是全称量词修饰的表达式,表示对于给定范围内的元素,每个元素都满足相应的约束;
      • \exists 表达式是存在量词修饰的表达式,表示对于给定范围内的元素,存在某个元素满足相应的约束;
      • \sum 表达式表示返回给定范围内的表达式的和;
      • \product 表达式表示返回给定范围内的表达式的连乘结果;
      • \max \min 表达式分别表示返回给定范围内的表达式的最大值和最小值;
      • <==> <=!=> 等价关系操作符: b_expr1<==>b_expr2 或者b_expr1<=!=>b_expr2 分别表示表达式相等或不等;
      • ==> <== 推理操作符: b_expr1 ==> b_expr2 或者 b_expr2 <== b_expr1
    • JML 中常用方法规格:
      • 前置条件 requiresrequires P 表示要求调用者确保 P 为真;
      • 后置条件 ensureensures P 表示方法实现者确保方法执 行返回结果一定满足谓词P的要求,即确保 P 为真;
      • 副作用范围限定:关键词 assignable 表示可赋值,modifiable 表示可修改;
      • pure :表示方法是纯粹的访问方法,不会对对象进行任何修改;
  • JML 的工具链我熟悉的有以下两种:
    • OpenJML 用于验证模块是否完成 JML 规定的功能;
    • JMLlauncher 图形用户界面工具的启动器;
    • JMLdoc 包含 JML 规范信息的 javadoc 版本;
    • JMLUnit 用于自定义测试模块是否符合需求,之后会详细讲述。

四、部署 JMLUnit 并测试模块

  • 部署 JMLUnit 的过程不算很复杂,从 GitHub 下载相应 jar 包,IDEA 安装 JUnit plugin,导入 jar 包,生成 JUnit 测试类即可;在 JUnit 测试类中用 assert 语句可以完成测试,如果不符合 assert 的要求则会报错,否则继续运行。
  • 下面是我手动编写的部分测试程序:
/**
*
* Method: containsEdge(int fromNode, int toNode)
*
*/
@Test
public void testContainsEdge() throws Exception {
//TODO: Test goes here...path3 = new MyPath(1, 1);graph.addPath(path3);System.out.println("Test contains edges.");Assert.assertTrue(graph.containsEdge(1, 1));
}/**
*
* Method: getShortestPathLength(int fromNode, int toNode)
*
*/
@Test
public void testGetShortestPathLength() throws Exception {
//TODO: Test goes here...graph = new MyGraph();path1 = new MyPath(10, 11, 12, 13);path2 = new MyPath(13, 14, 15);path3 = new MyPath(11, 15);graph.addPath(path1);graph.addPath(path2);graph.addPath(path3);System.out.println("Test get shortest path.");Assert.assertEquals(graph.getShortestPathLength(10, 15), 2);}
  • 下面是我的 JUnit 运行情况:

  • 可以看出对我想要测试的类都完成了测试,并正确输出。

五、收获与总结

  • 通过这个单元的三次 JML 作业,我认识到了 JML 的强大之处,它相当于调用者与函数之间的一个承诺,我给你一个输入,你必须返回相应的输出或抛出异常,这也是今后工作中会比较常见的完成工作的方式,需求通过 JML 给我们,我们完成相应的算法。
  • 虽说这个单元是 JML 规格的练习,但在实际编写程序时,我反而不会细细研读 JML ,因为从指令的要求以及方法名也能看出某个方法的作用是什么,所以我希望多增加一些类似实验课上写 JML 的练习,可以督促我们更深刻地学习到 Java 建模语言。
  • 话说回来,这个单元的三次作业其实也不算难,部分简单的 JML 中甚至给出了完成这个算法的方法,不过尤其是第三次作业,我觉得太偏向数据结构了,我甚至在地铁系统中用了不下十个 HashMap ;总的来说,这次规格的单元作业,我又掌握了新的领域的内容,收获还是蛮丰富的。

转载于:https://www.cnblogs.com/delicate1989/p/10902380.html

JML 规格设计分析相关推荐

  1. JML规格编程——BUAA OO第三单元作业总结

    整体概述 这个单元整体围绕Java Model Language(JML)展开,通过学习JML规格了解契约式编程的过程,课上实验中进行了JML规格的简要编写,课下实验主要通过阅读规格并按照规格的要求正 ...

  2. OO第三单元总结——JML规格

    一.JML简介 1.JML语言的理论基础 JML(Java Modeling Language)是用于对Java程序进行规格化设计的一种表示语言.JML是一种行为接口规格语言 (Behavior In ...

  3. 第三单元JML规格总结

    第三单元学习了JML规格描述语言,根据JML的规定编写对应的方法,同时也复习了数据结构的知识,并且也考察了程序的时间复杂度. 一.JML语言 理论基础 JML全名为Java Modeling Lang ...

  4. JML规格单元梳理总结

    前言 其实直到这个单元结束,对JML的理解也不是很深,对JML最直观的看法就是对着JML规格写代码很舒服,还有JML真的不怎么好写. 当然,针对这三次作业来谈,其实并不是很理解JML在这次作业中占据的 ...

  5. 第三单元总结:JML规格定义下的程序设计、验证与测试

    JML语言及工具 JML语言理论 JML语言利用前置条件.后置条件.不变式等约束语法,描述了Java程序的数据.方法.类的规格,是一种契约式程序设计的实现工具. 常用的JML语言特性 \result: ...

  6. OO第三单元JML规格总结分析

    OO 第三单元博客作业 1. JML语言概述 1.1 理论基础 综述 Java建模语言(Java Modeling Language,JML)是一种进行详细设计的符号语言,使人们用一种全新的方式来看待 ...

  7. BUAA OO Unit3 JML规格

    前言 这是2021级BUAA 面向对象课程第三单元实验--基于规格的层次化设计的博客总结. 架构设计 本单元作业需要根据 JML 规格描述实现一个社交关系模拟系统,需要阅读JML,实现高效图算法以及异 ...

  8. oo第三次博客-JML规格

    这三周的作业主要是围绕以JML来约束代码开发,以确保程序的正确性与鲁棒性. Part 1:三次作业的实现与bug 第一次作业没有任何算法和数据结构上的难度,对于Path和PathContainer的各 ...

  9. OO——第三单元JML规格编程总结

    一.JML理论基础及应用工具链 JML存在的意义 1. 开展规格化设计,能够实现设计与实现分离,实现进行提前测试. 2. 方便程序代码的阅读和维护. JML方法规格 requires -- pre-c ...

  10. BUAA_OO第三单元作业总结——JML

    BUAA_OO第三单元作业总结--JML 单元任务 本单元的主要内容是熟悉JML相关的理论知识,能够根据JML规格实现对应方法,通过一步步实现地铁系统来熟悉JML规格. 一.JML语言的理论基础.应用 ...

最新文章

  1. 函数指针到文本反汇编
  2. 她是数学奇女子,巴贝奇的好友,却没能等到计算机的辉煌时刻
  3. 测试MM32F3277中的MicroPython的Signal功能
  4. IDEA下SpringBoot项目的引用类没问题却提示:java:找不到符号:类**位置:程序包
  5. Python 字符串/列表/元组/字典之间的相互转换 - Python零基础入门教程
  6. MAVEN项目的搭建
  7. android投屏小米盒子,Mibox S 小米盒子国际版:可能是 2019 新年最值的原生 AndroidTV...
  8. 【CVPR华为】【CVPR诺亚方舟】【CVPR2019】华为诺亚方舟实验室2019年CVPR27篇:全面展现诺亚实验室在计算机视觉蓝图
  9. Python中Oracle的连接、增删改查
  10. Vivado工程配置petalinux实现linux下网卡驱动
  11. 每当图片传过来时进行对比_每当应用开始使用Mac的网络摄像头时如何获取通知...
  12. 暴力破解:破解强力保护、IP 封锁(连续提交 3 次错误登录封IP 的情况下)
  13. 如何在Visual Studio中自动格式化代码?
  14. 《高效学习法》思维导图——Jan
  15. 指纹辨识传感器解决方案
  16. 设计原则与思想:设计原则12讲
  17. centos 中止 nodejs_今日热点游戏新闻!守望先锋2有望2月推出;心跳回忆新作将登陆NS;莱莎炼金工房2实体版中止发售;2K21加载画面广告...
  18. [InteliJ IDEA] 系统资源不足
  19. 我对COSCO的SWOT分析
  20. 小明兄短视频引流变现必火课,最强DOU+玩法 超级变现法则,两天直播间涨粉20W+

热门文章

  1. matlab 四叉树表达,已知二值图像,如题图8.4所示。 (1)对该图像使用四叉树进行划分; (2)用四叉树表达该图像。 - 试题答案网问答...
  2. 小白分分钟学会,简单四步,直接把sql直接转换成接口服务java
  3. 贪吃蛇代码--c语言版 visual c++6.0打开
  4. 8192fu网卡linux,Ubuntu 折腾 RTL8192EU 无线网卡驱动
  5. Fabric环境配置
  6. Eclipse SVN还原文件到历史版本详解
  7. webgame源码下载及网页游戏开发资源精华集合
  8. erp软件涉及哪些计算机技术?,ERP软件应该学习哪些内容?
  9. mysql有mdf文件和ldf文件吗_mdf与ldf文件格式
  10. 99se.PCB技术大全