这三周的作业主要是围绕以JML来约束代码开发,以确保程序的正确性与鲁棒性。

Part 1:三次作业的实现与bug

第一次作业没有任何算法和数据结构上的难度,对于Path和PathContainer的各个方法的实现按照给出的规格复读即可。唯一的难点(大约也不算难点)便是将NodeId进行映射,用hashmap就好,不过注意不要做一个调包侠,hashmap中有的方法譬如遍历很慢,虽然看上去只差常数,但是这个常数巨大,如果在第一次作业中不加处理就会在第二次作业中TLE。

第一次作业也让我们了解了抛异常,我个人认为JML对于抛异常的处理是值得称道的,通过这样的约束可以控制程序在犯了一些明显的错误后及时停止而不是越错越远浪费计算资源,造成更严重的后果。

第二次作业是在第一次的基础上写一个Graph类,这个类继承PathContainer,将不同的Path汇总成一个图,并能够查询最短路。

对于第二次作业,首先要吐槽的是给出的接口,在需要继承的情况下应该声明为protect,才能更好地实现数据的继承,而给出的接口使用了private,给我们的选择便只有重新声明数据,每当使用的时候get一次以更新或者将第一次PathContainer的代码复制到Graph中,我为了偷懒选择了后者,结果第三次就只能靠疯狂压行来改正代码风格。

对于第二次图的实现,介于图中边权均为1,求最短路和是否连通均可以使用BFS。在BFS中将查找到的点均进行更新就好,这样,在询问两点是否连通或者他们的最短路时,可以先查找对应图中两点间值是否为初始值,若是则BFS查找更新,否则直接返回结果。同时只有当需要查找两点间最短路或者连通情况且Path有过remove或add且上一次Path改变后没有更新才更新图。

对于第三次作业,其实是在求带权最短路。这里再使用BFS就不太合适了。

对于连通块数量,可以使用并查集,也可以选择图中一个点开始BFS,终止后若没有遍历所有点则选择一个未遍历的点继续BFS,如此往复至图中所有点被搜索过即可。这两者后者更快。

对于三种不同的最短路,王嘉仪同学给出的关于图的数学性质是正确的,利用这个性质我们可以更简洁的完成最短路。

以最短花费为例,设边权为1,跨路径一次消耗2,则最终消耗=边数+2*换乘数-2,此时,对于同一路径内任意两点,我们先求出图内floyd最短路图,将其中的值全部加上2,再将这些图合并后使用迪杰斯特拉求出两点间最短路,得到的值减去2就是正确答案。注意求起点a到终点b的最小花费时,使用迪杰斯特拉算法更新的点答案均是正确的,所以若是询问的两点的最短路值不是初始值就可以直接输出了。其余几种最短路可以类推。

这三次作业只有最后一次有bug,我将最短路的图设置为了1000,没想到UnpleasentValue的最小值超过了1000.

关于这三次作业的不足,我觉得最大的问题在于继承复用上。因为接口里给出的类型是private,没有办法使用protected继承数据,导致继承时需要把所以数据使用时get一次,而我选择了偷懒的办法,直接将被继承的代码写入了新的代码中,这导致我第三次作业的Railway很长很丑。

Part 2:关于JML

JML(Java Modeling Language)是用于对Java程序进行规格化设计的一种表示语言。

JML能够用形式化语言来规范代码,提高代码可维护性。

JML以注释形式存在,每行以@开始,分为行注释(表示为//@......)和块注释(表示为/*@......@*/)。

JML有原子表达式,量化表达式,集合表达式等等,以及约束类型的类型规格和约束方法的方法规格。

原子表达式有\result和\old()两种,前者用来约束一个方法的返回值,后者用来表示括号内内容在方法执行前的内容。

量化表达式有forall,\exists和\sum,forall表示某范围内的元素均应满足某条件,为全称量词,相应的\exists为存在量词,而\sum返回的是给定范围内表达式的和。

集合表达式则构造一个容器,明确其包含的元素。

操作符包含子类型操作符<,等价操作符<==>,不等价操作符<=!=>,推理操作符==>,上述操作符均返回bool型值。

对于方法规格,我们通过requires语句约束前置条件,通过ensures语句约束后置条件,同时JML也给出了副作用、异常的约束,通过saaignable和modifiable来约束副作用,并利用signals来抛异常。

对于类型规格,主要利用不变式invariant P来进行约束。

部署JML UnitNG/JML Unit

安装后,编写测试样例如下:

测试结果如下:

关于JML的使用,我个人感觉它只应该是一种严格的约束。事实上,我们的代码和JML都是形式化语言,而我们使用JML是为了自然语言表述不清导致代码bug。

我认为,规格应该是宏观的,整体的,针对于方法的输入输出形式,而不应该是对于代码实现的全盘描述,若是后者,那写代码岂不成为了对于规格的翻译?那我们为什么不直接写规格?规格应该是规范而不涉及具体的内部实现。

举个例子,形式化的规格语言可以作为伪代码来描述算法,我们利用这种形式化的语言来详尽的描述算法,在用java语法来翻译规格语言,这显然是在做重复无谓的工作。

在这几次作业中,尤其是最后一次作业,我们可以发现,新增的方法具有大量的规格,不少同学都吐槽过这个规格又臭又长,而我发现这些又臭又长的规格真正有用的部分是在于对于输入输出数据合法性判断以及抛异常的部分,剩下的部分其实是在表达算法思想,而我认为描述算法不应该是规格应该做的。

oo第三次博客-JML规格的更多相关文章

  1. OO第三次博客作业——规格

    OO第三次博客作业——规格 一.调研结果: 规格的历史: 引自博文链接:http://blog.sina.com.cn/s/blog_473d5bba010001x9.html 传统科学的特点是发现世 ...

  2. [BUAA OO]第三次博客作业

    OO第三次博客作业 1. 规格化设计的发展 我认为,规格化设计主要源自于软件设计的两次危机.第一次是由于大量存在的goto语句,让当时被广泛应用的面向过程式的编程语言臃肿不堪,在逻辑性上与工程规模上鱼 ...

  3. 2019年北航OO第三次博客总结

    一.JML语言理论基础及其工具链 1. JML语言理论基础 JML是用于对Java程序进行规格化设计的一种表示语言,是一种行为接口规格语言(Behavior Interface Specificati ...

  4. oo第三单元博客作业

    JML语言理论基础 Java建模语言(Java Modeling Language,JML)是一种进行详细设计的符号语言,他鼓励你用一种全新的方式来看待Java的类和方法.JML是一种行为接口规格语言 ...

  5. OO第三次博客作业(第三单元总结)

    (1)梳理JML语言的理论基础.应用工具链情况 Java 建模语言(JML)将注释添加到 Java 代码中,这样我们就可以确定方法所执行的内容,而不必说明它们如何做到这一点.有了 JML,我们就可以描 ...

  6. 渡过OO的死劫,了解规格的意义——OO第三次博客总结

    当熬过了一次次黑暗,迎接我们的却是被扣的惨不忍睹的JSF ┭┮﹏┭┮ 一.总结调研 规格的历史 传统科学的特点是发现世界,而软件的特点是构造世界.软件的最底层就是0,1,两个离散的值.程序设计语言的三 ...

  7. OO第三次博客作业---透过代码看设计

    不得不说的JSF 经过前几次作业的煎熬.出租车的代码量不断地增多.而出租车问题在不断的完善,这也就牵涉到一个问题,那就是最初出租车程序的设计问题,如果一开始设计的就有问题的话,那么在后来的过程中就会遇 ...

  8. OO第三次博客作业--第三单元总结

    一.JML 语言的理论基础及应用工具链 JML 是一种行为接口规格语言,提供了对方法和类型的规格定义手段.通过 JML 和其支持工具,不仅可以基于规格自动构造测试用例,并整合了 SMT Solver ...

  9. OO第三次博客作业

    一.规格化的发展历史 最早的程序设计都是面向机器,从一开始使用的机器语言,到后面的汇编语言,都是面向机器的语言,编写困难也容易出错.随着需求的发展,程序的编写从面向机器走向面向过程,但由于goto语句 ...

随机推荐

  1. 依赖注入Bean属性——手动装配Bean

    一.构造方法注入 其中,可以根据不同的参数列表调用不同的重载的构造方法: 其中,基本数据类型没有包,引用类型都有包路径,基本类型对应封装类: 二.通过property标签调用类的set方法注入 三.通 ...

  2. BeanFactory和ApplicationContext对比

    一.BeanFactory和ApplicationContext对比 其中,ApplicationContext容器即时加载,就是一加载配置文件,就会创建对象,且自动装配bean(即写道xml中bea ...

  3. 路由懒加载---Vue Router

    一.什么是懒加载? 懒加载也就是延迟加载或者按需加载,即在需要的时候进行加载. 二.为什么在Vue路由中使用懒加载? 像vue这种单页面应用,如果没有应用懒加载,运用webpack打包后的文件将会异常 ...

  4. golang 判断平台是32位还是64位

    在strconv包中有个常量 const intSize  =  32  <<  (  ^uint(0)  >>  63  ) const IntSize = intSize ...

  5. 学习了解PHP中的SeasLog日志扩展

    今天来学习的扩展是和日志相关的一个扩展,对于 PHP 的日志应用来说,除了本身自带的 error_log() . syslog() 之外,在大多数的框架中还会经常见到 monolog 的踪影.当然,我 ...

  6. PHP中的对象比较

    在之前的文章中,我们讲过PHP中比较数组的时候发生了什么?.这次,我们来讲讲在对象比较的时候PHP是怎样进行比较的. 首先,我们先根据PHP文档来定义对象比较的方式: 同一个类的实例,比较属性大小,根 ...

  7. 用 shell 脚本做命令行工具扩展

    问题的提出 公司开发机与远程服务器之间有严格的隔离策略,不能直接使用 ssh 登录,而必需通过跳板机.这样一来,本地与服务器之间的一些文件传输变得非常不便.经过咨询,运维教了我一招: $ nc -l ...

  8. Linux系列(10) - 命令搜索命令whereis与which

    whereis 只能搜索系统命令,不能搜索自己凭空创建的普通文件 命令格式: whereis [命令名] 选项: -b:只查找可执行文件 -m:只查找帮助文件 which 搜索命令所在路径及别名:不是 ...

  9. linux帐户安全管理与技巧

    实验环境 CentosOS5.6试验台. 任务一:建立与删除普通用户账户,管理组 1)创建一个新用户user1 useradd user1 查看用户是否创建成功 2)创建一个新组group1 grou ...

  10. 鸿蒙内核源码分析(源码结构篇) | 内核每个文件的含义 | 百篇博客分析OpenHarmony源码 | v18.04

    百篇博客系列篇.本篇为: v18.xx 鸿蒙内核源码分析(源码结构篇) | 内核每个文件的含义 | 51.c.h .o 前因后果相关篇为: v08.xx 鸿蒙内核源码分析(总目录) | 百万汉字注解 ...