OO第三单元的作业主题是JML规格化设计,作业以图及图的最短路径相关计算为载体,体现接口的规格化设计。

-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

一、JML语言的理论基础和应用工具链

JML是一种形式化的、面向JAVA的行为接口规格语言(behavioral interface specification language),它混合了Java的语法成分和JML引入的语法成分,能描述一个类的不变式等限制条件,也能描述方法的前置条件、副作用、后置条件等。利用JML,我们可以做到先思考这个类的规格,之后再去考虑具体实现的问题,这样做到了可扩展性强,并且可以根据规格,对方法直接进行单元化测试,避免了大规模的测试可能带来的覆盖不全面的问题,符合面向对象的思想。

JML有相应的的工具链,来自动识别和分析处理JML语言。OpenJML是专门针对JML语言设计的一个验证工具,它可以检查JML规格语法的正确性,也可以根据方法的JML语言和方法具体实现的代码来初步地验证方法实现的是否符合规格。JUnit是一个对代码进行单元测试的插件,它可以针对某一个方法,利用assert断言语句,实现自动化测试,使用时,可以根据该方法的规格构造测试用例,这样可以帮助我们快速定位到bug的位置,不用看着一大段一大段的程序去调试了。SMT Solver是一个用来静态检查程序的代码实现是否符合JML规格的插件,与JUnit不同的是,它不需要用户提供测试用例,而是执行静态的检查,来进行形式化的验证。

二、利用JMLUnit和JUnit进行单元测试

1、利用JMLUnit进行JML语言的单元测试

JMLUnit是一个针对JML语言的单元测试工具,它能根据我们写的JML语言,提供一些包括边界数据在内的测试用例,来检查JML语言的正确性。在写了一个简单的整数比大小方法compare之后,对其进行JMLUnit的检查,compare方法的代码如下:

对其进行JMLUnit单元检查后,检查结果如下:

检查结果说明compare方法的JML描述通过了所有的测试点。

2、利用JUnit进行针对Graph接口的单元测试

由于Graph接口是从PathContainer接口继承而来,因此只测试Graph之中与PathContainer不同的接口,这些接口的实现也是第二次作业中的重点。针对不同的接口的测试代码如下:

addPath接口:

removePath接口:

removePathById接口:

getShortestPath接口:

在构造测试用例时,应该注意既要考虑规格中的正常情况(normal_behavior),也要考虑异常情况(exceptional_behavior)。同时,也应该加入一些特殊的边界样例,如Path(3,3,3),全部是自环且合法的Path,以验证程序的鲁棒性。

三、我的架构设计

显然,这三次作业的架构是很有逻辑上的继承关系的,因此我首先考虑使用继承,但是在使用的过程中遇到了子类无法访问父类的private属性的问题,而checkstyle又要求类的属性必须是private,当时我没有想到好的解决办法,就放弃了继承。

第一次作业的类图如下:

第二次作业的类图如下:

第三次作业的类图如下:

这三次作业中,对于最短路径的计算的要求是逐次递进的:第一次作业没有要求计算最短路径,第二次作业要求计算最短路径,第三次作业要求计算最短路径、最少换乘、最低票价、最小不满意度。因此对于边的信息要求也是越来越细致的,鉴于CPU时间限制了时间复杂度,这就要求在每次add或removePath的时候要对图的相关信息进行计算,将最短路径等信息直接计算出来并保存,在查询最短路径时直接输出即可,这是一种牺牲空间换取时间的思想。在我的架构中,存在很多HashMap来存储这些边和节点的信息,有的信息甚至以多种方式存了多遍,这就是利用存储冗余的信息来加快程序运行速度的方法。在每次增加新的需求时,都要考虑如何应该保存图的什么信息、如何保存这些信息,以达到简便计算的效果。这是每次修改代码或重构时应该考虑的很重要的一点。

四、代码中的bug

本单元的三次作业在需求上并没有前两个单元复杂,难点主要在于算法,如何以较低的时间复杂度的算法完成对最短路径的计算是考虑的重点。下面将就三次作业来分析我的代码中的bug。

第一次作业:代码中出现了严重的逻辑bug,在ComparePath时并没有严格按照字典序比较,导致在比较两个不同长度(节点序列长度不同)的路径时会出现bug。这个严重的bug在强测和互测中都被找了出来。

第二次作业:最短路径的计算采用基于邻接矩阵的Floyd算法,强测和互测中均未发现bug,也没有出现CPU超时的情况。

第三次作业:最短路径、最少换乘、最低票价、最小不满意度的计算仍然采用Floyd算法,在计算不同类型的最短路径时,生成不同的权值矩阵传入Floyd算法中即可。强测中未发现bug,互测被hack了一组CPU_TLE,是由于我的算法每次add和removePath的时候都要重新计算所有的最短路径,并且未采用缓存的机制,导致计算太慢,CPU超时,可以考虑采用更高效率的算法,或者使用更好的图的结构来减少计算,以避免这个问题。

-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

心得体会

本单元的主题是JML规格化设计,通过本单元的学习,我初步掌握了JML有关的知识。在拿到一个要求的时候,首先应该想到的不是用什么算法去实现,而是应该先想规格怎么写,在很大程度上,规格写的准确与否决定了这个类的设计会不会出现问题,如果规格中就有模糊不清的地方,或者是没有考虑全面的地方,那么照着这个规格实现出的类或方法肯定是有问题的,而且这种错误不好去定位。正所谓“磨刀不误砍柴工”,在实现一个类之前,如果先把规格写好,那么之后的具体代码实现就不是大问题了,或者说,即使代码实现中有问题,也能通过单元测试的方式快速定位并改正问题;但如果没有一个好的规格就去直接实现类的话,那么在实现的过程中就可能会遇到各种模糊不清的地方,甚至出现“拆东墙补西墙”的情况,de掉一个bug的同时又多出好几个新的bug,这样的写代码体验是极差的,而出现这些问题的根本原因,就是在写代码的时候我们其实并不那么清楚这个类要干什么、这个方法有哪些前置条件、会修改哪些值,规格化语言就可以在一定程度上帮助我们避免这个问题。

2019OO第三单元作业总结的更多相关文章

  1. OO第三单元作业总结

    OO第三单元作业总结--JML 第三单元的主题是JML规格的学习,其中的三次作业也是围绕JML规格的实现所展开的(虽然感觉作业中最难的还是如何正确适用数据结构以及如何正确地对于时间复杂度进行优化). ...

  2. 【OO学习】OO第三单元作业总结

    [OO学习]OO第三单元作业总结 第三单元,我们学习了JML语言,用来进行形式化设计.本单元包括三次作业,通过给定的JML来实行了一个对路径的管理系统,最后完成了一个地铁系统,来管理不同的线路,求得关 ...

  3. BUAA OO 2019 第三单元作业总结

    目录 总 JML规格化设计 理论基础 工具链 规格验证 验证代码 代码静态检查 自动生成测试样例 生成结果 错误分析 作业设计 第九次作业 架构 代码实现 第十次作业 架构 代码实现 第十一次作业 架 ...

  4. OO第三单元作业——魔教规格

    OO第三单元作业--魔教规格 JML的理论基础和相关工具   JML(Java Modeling Language,Java建模语言),在Java代码种增加了一些符号,这些符号用来标志一个方法是干什么 ...

  5. OO第三单元作业(JML)总结

    OO第三单元作业(JML)总结 目录 OO第三单元作业(JML)总结 JML语言知识梳理 使用jml的目的 jml注释结构 jml表达式 方法规格 类型规格 SMT Solver 部署JMLUnitN ...

  6. OO第三单元作业小结

    一.JML理论基础及应用工具链情况 理论基础 1.JML表达式 \result:表示方法执行后的返回值. \old(expr):表示一个表达式expr在相应方法执行前的取值. \foall:全称量词修 ...

  7. 2019北航OO第三单元作业总结

    1.梳理JML语言的理论基础.应用工具链情况 JML基础理论: JML(Java Modeling Language)是用于对Java程序进行规格化设计的一种表示语言.JML是一种行为接口规格语言,基 ...

  8. 北航OO第三单元作业总结(3.1~3.3)

    JML简介及相关工具链使用 1.JML规格描述语言介绍 本单元学习的内容是JML规格描述语言.我们知道,面向对象方法是一个抽象过程,需求者仅需关注方法的规格.规格是对一个方法/类/程序的外部可感知行为 ...

  9. 2019OO第四单元作业总结&OO课程整体总结

    第四单元作业总结 第四单元的作业主题是UML图的解析,通过对UML图代码的解析,我对UML图的结构以及各种元素之间的关系的理解更加深入了. ------------------------------ ...

随机推荐

  1. sql常用查询命令

    目录 SQL Server常用查询命令: 查看当前时间 查询所有数据库名 查询当前使用的数据库名 查询前几条数据 去重查询 字段换名 查询不等于 查询在两个值之间数据 查询条件或 模糊匹配查询 查询为 ...

  2. [Linux系列]DNS系列理论笔记与DNS服务器配置

    0x01 基础术语 DNS(Domain Name System,域名系统),域名和IP地址相互映射的一个分布式数据库,简而言之就是通过更易记忆的域名代替IP去访问一个网站. FQDN(Fully Q ...

  3. 模板引挚 jade ejs

    // asl sum翡翠 后台使用如下: const jade = require('jade') //pretty 美化的意思,指的是渲染的布局会美化   2020-2-15 var str = j ...

  4. Mac下Sublime Text3配置Python开发环境

    设置Sublime Text的语法为python View -> syntax ->python 设置编译环境(默认python版本2.7) Tools -> Build Syste ...

  5. 《挑战程序设计竞赛》——DFS

    DFS(深度优先搜索) 简介 深度优先搜索(DFS,Depth-First Search)是搜索的手段之一.它从某个状态开始,不断的转移状态直到无法转移.然后退回到前一步的状态,继续转移到其他状态,如 ...

  6. Ts基本数据类型

    TS的基本数据类型 string let str : string str = 1 //报错 会提示num是字符串 不是数字 str = 'test' //正确 //拼接字符串 let str2 : ...

  7. Linux系类(8) - 文件搜索命令locate

    文件搜索命令locate 命令格式 locate [文件名] 在后台数据库中按文件名搜索,搜索速度更快,而find.which是遍历所有目录去查找:后台数据库在/var/lib/mlocate (保存 ...

  8. Windows环境下搭建Hadoop(2.6.0)+Hive(2.2.0)环境并连接Kettle(6.0)

    前提:配置JDK1.8环境,并配置相应的环境变量,JAVA_HOME 一.Hadoop的安装 1.1 下载Hadoop (2.6.0) http://hadoop.apache.org/release ...

  9. if 条件

    返回不能被2整除的数 result = [] iter = range(10) for i in iter: if i % 2: print(f'{i}', i % 2) result.append( ...

  10. 深度学习--GAN学习笔记

    生成模型 WGAN Blog GAN 推荐学习网站 生成模型 什么是生成模型? GMM: 用来做聚类,(非监督学习) NB(朴素贝叶斯):(监督学习,可以用来做垃圾邮件分类) Logistics 回归 ...