这三周的作业主要是围绕以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. 斐波那契数(Java)

    斐波那契数,通常用 F(n) 表示,形成的序列称为 斐波那契数列 .该数列由 0 和 1 开始,后面的每一项数字都是前面两项数字的和.也就是: F(0) = 0,F(1) = 1 F(n) = F(n ...

  2. Java-SpringBoot整合SpringCloud

    SpringBoot整合SpringCloud 1. SpringCloud特点 SpringCloud专注于为典型的用例和扩展机制提供良好的开箱即用体验,以涵盖其他情况: 分布式/版本化配置 服务注 ...

  3. C# Collection

    数组与集合不同的适用范围: 数组:数组最适用于创建和使用固定数量的强类型化对象. 集合:集合提供更灵活的方式来使用对象组. 与数组不同,你使用的对象组随着应用程序更改的需要动态地放大和缩小. 对于某些 ...

  4. 小狐狸钱包怎么使用?MetaMask(小狐狸) 使用教程 - 如何添加BSC链、Heco链

    MetaMask介绍 MetaMask是一款在谷歌浏览器Chrome上使用的插件类型的以太坊钱包,只需要在谷歌浏览器添加对应的扩展程序即可使用. 1.Download & Install: 官 ...

  5. Ansible快速实战指南----多机自动化执行命令、部署神器

                                      1.需求: 需要在多台主机上,发送文件.执行命令,进行快速部署 2.ansible 远程复制文件 例子:在当前节点(20.88.14 ...

  6. 为什么在匿名内部类中引用外部对象要加final修饰符

    当所在的方法的形参需要被内部类里面使用时,该形参必须为final. 为什么必须要为final呢? 首先我们知道在内部类编译成功后,它会产生一个class文件,该class文件与外部类并不是同一clas ...

  7. PHP设计模式之命令模式

    命令模式,也称为动作或者事务模式,很多教材会用饭馆来举例.作为顾客的我们是命令的下达者,服务员是这个命令的接收者,菜单是这个实际的命令,而厨师是这个命令的执行者.那么,这个模式解决了什么呢?当你要修改 ...

  8. 配置阿里云gradle

    build.gradle buildscript { ext { springBootVersion = '1.5.15.BUILD-SNAPSHOT' } repositories { // mav ...

  9. Linux下实现高可用软件-Keepalived基础知识梳理

    Keepalived介绍 Keepalived软件起初是专门为LVS负载均衡软件设计的,用来管理并监控LVS集群系统中各个服务节点的状态,后来又加入了可以实现高可用的VRRP功能.因此,Keepali ...

  10. 华为云计算IE面试笔记-eBackup有哪几种备份组网方式,各备份组网方式主要的应用场景及备份流程?

    应用场景: LAN-Base一般用于备份数据量小,且对备份窗口没有特殊要求的场景,此类场景下备份服务器和备份代理一般是虚拟机部署. LAN-Free一般用于备份数据量较大,且对备份窗口要求比较严格的场 ...