OO博客作业-《JML之卷》
OO第三单元小结
一.JML语言理论基础以及应用工具链情况梳理
一句话来说,JML就是用于对JAVA程序设计逻辑的预先约定的一种语言,以便正确严格高效地完成程序以及展开测试,这在不能容忍细微错误的工程领域如航空航天领域有广泛应用。
1.1 JML语言理论基础
本单元我们学习了一些语言理论基础,梳理如下:
1.requires 该子句定义了方法的前置条件
2.assignable子句,列出方法修改的类成员属性。\nothing则表示方法不改变任何成员属性,是一个pure的方法
3.ensure子句,定义了后置条件,如返回的结果或者该方法运行后的逻辑结果等等
4.\result表达式,表示方法返回的逻辑上的正确的结果
5.\old(expr),表示执行相应方法前表达式expr的取值
6.public normal_behavior表示方法的正常功能
7.public exceptional_behavior表示方法的异常功能
8.signals 定义了抛出某异常以及抛出异常的条件语句expr,当expr为true时抛出异常
9.signals_only,强调满足前置条件时候抛出相应异常
10.invariant,定义了一个方法的不变的属性
以及一些量化表达式,集合逻辑表达式等等,在JML手册中有详细介绍,在此就不一一梳理了。
主要是要理解JML对于JAVA程序设计与实现的分离的作用以及其对于整个程序的架构设计以及正确性保证上的重要性。我个人的体会是,在我们的作业中读懂JML其实该次作业就完成了一半了。
1.2 工具链简介
与规格化设计相关的工具主要有:OpenJML,JUnit,JUnitNG等等,Openjml主要帮助我们检查规格化语言JML的语法以及基本逻辑正确性,Junit以及JunitUG则是对JML规格进行测试,前者主要用于单元测试以及一定的自动化测试,后者则主要测试一些边界情况。
二.JMLUnit部署以及其使用
根据zwc大佬在讨论区发的一篇博客上的步骤部署好JMLUnit后,编写测试类:
import org.junit.After;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
public class MyPathTest {
private MyPath path1, path2, path3;
@Before
public void before() {
path1 = new MyPath(1, 2, 3, 4);
path2 = new MyPath(1, 2, 3, 4);
path3 = new MyPath(1, 2, 3, 4, 5);
}
@Test
public void testEquals() throws Exception {
Assert.assertTrue(path1.equals(path1));
Assert.assertTrue(path1.equals(path2));
Assert.assertFalse(path1.equals(path3));
Assert.assertTrue(path2.equals(path1));
Assert.assertTrue(path2.equals(path2));
Assert.assertFalse(path2.equals(path3));
Assert.assertFalse(path3.equals(path1));
Assert.assertFalse(path3.equals(path2));
Assert.assertTrue(path3.equals(path3));
}
}
运行后,结果如图,与预期结果一致:
三.作业架构设计梳理
第一次:
第二次
第三次
第三次作业数据结构层如图:
总地来说,三次作业我都运用了Floyd计算最短路以及第三次作业用dfs计算连通块。三次作业架构类似,主要还是在"MyPathContainer"上不断增加数据结构管理相关数据以及增加新的计算方法,实际上,将计算逻辑以及数据结构包装在另外的单独的类里面,我觉得会是更好的设计方式。
这三次作业关键在于数据结构的选择以及时间复杂度的控制,首先将节点编号做一个1-122的映射(Hashmap<real_Id,x_Id>),并采用节点回收机制,这样就可以进行静态数据的玩法了。实际上,无论是两点之间的最短路,还是最少换乘,最低票价亦或最低不满意度,都可以归结为最短路问题的求解,只不过后面三个需要有其他数据结构来支撑,以便构建起正确的边权。当构建好所有的图结构后,一个floyd算法,就可以解决一切。每次加路径以及去除路径的时候,计算好对应的数据,查询的时候就是O(1).
四.bug与修复情况
这次作业由于选择了比较好的数据结构以及求解相关查询的方法,所以本次我自己的作业公测与互测都没有bug。但是在完成作业的时候,仍然在本地测试的时候发现一些bug:
1.在第二次作业的时候,由于我在去边的时候,先删除点再去边,这样的逻辑错误会导致边集数组的访问会出现访问不存在的两点的边。
2.在第三次作业的时候,我采用最原始的dfs来进行连通块的查询,当时网上给出的算法是n个节点,而我定义的MAXNODE为122(大于等于120均可),这样当图中不同节点比较少的时候,我得到的答案是靠近120,当时我懵了好久,是网上写错了吗?思考下发现,由于我们已经加入的path的不同节点很可能是少于120的,所以每次从编号0-122遍历dfs的时候,要先查询该编号是否在映射表中(Hashmap<real_Id,x_Id>),如果存在并且节点没有被访问过才把答案加1,修改之后我连通块的计算就算是完成了。
3.在第三次作业的时候,我会出现查询最少票价的时候返回值是MaxLength=666666666,查看之后,是在增加路径的时候,把对票价数组的对称赋值写成了对相同节点的赋值,导致神必错误。
关于互测:
对拍器是很容易的,主要还是在于数据生成器的强弱。
三次作业我发现了也仅发现了一次别人的bug,就是最大值估计错误,当加入的每条path都不在已有path中存在,并且最大节点数为120的时候,会出现越界错误,这个bug要修起来可能不仅仅是把数组开大这么简单,要牺牲大部分性能或者甚至重构。
五.对规格撰写的心得体会
规格撰写对于像我这样的小白来说,上手难度其实不大,理解基本语法和关键语句,看着已有的例子,其实要写一份较为简单的规格描述比较容易。但是想要完整的针对一次作业,从零开始设计架构,编写规格,完成程序,我觉得还需要更多的学习。
我个人认为,由于Openjml环境比较苛刻,所以想要写出一份语法完全正确的规格描述其实很困难或者说是要花的时间远远比完成程序多。所以,规格撰写在初级阶段,关键要在于逻辑的严密性和正确性,这是保证完整规格化设计后的程序正确性的重要前提。这三次作业的体验明显好于第1、2单元,原因在于每次作业新增需求都不需要重构,只需要在已有的程序上加入一些新的用于管理数据的数据结构和相应的方法罢了,第三单元的每次作业的可拓展性都远远好于之前两个单元我完成的每次作业。可以看见,架构设计对JAVA程序可拓展性和可维护性的重要性。
最后,摆个队形,祝愿OO越来越好,可以让更多的同学和学弟学妹学到更多更多的知识,提升更多更多的能力。
OO博客作业-《JML之卷》的更多相关文章
- OO博客作业1:第1-3周作业总结
(1)基于度量来分析自己的程序结构 注:UML图中每个划分了的圆角矩形代表一个类或接口,箭头可代表创建.访问数据等行为.类的图形内部分为3个部分,从上到下依次是类的名称.类包含的实例变量(属性).类实 ...
- OO博客作业3:第9-11周作业总结
一.总结介绍规格化设计的大致发展历史和为什么得到了人们的重视 1.规格化设计的大致发展历史 规格化设计,又称契约式设计,最早由Bertrand Meyer于1986年提出,出自于<面向对象软件构 ...
- BUAA_OO第三单元总结性博客作业——JML
一.JML 在第三单元的面向对象课程中我们第一次接触了JML语言以及基于JML规范的规格化设计.在之前一系列关于面向对象思想的学习认识中,我们知道了Java是一种面向对象的语言,面向对象思想的一个重要 ...
- 第四次oo博客作业
(1)本单元是撰写UML数据分析器,架构大致如下,在指导书要求的函数外,对于UmlClass类,Umlinterface类,以及状态机,顺序图这四个类重现构造一个类,这个类里有他们所需要的全部信息,另 ...
- OO博客作业4:第13-14周作业总结
一.论述测试与正确性论证的效果差异,比较其优缺点 测试是设计若干组测试用例,运行程序并检验其是否完成预期功能.测试是一种直接发现BUG的方法,可以准确断定什么样的BUG会发生,并通过辅助调试进一步确定 ...
- OO博客作业2:第5-7周作业总结
(1)从多线程的协同和同步控制方面,分析和总结自己三次作业来的设计策略及其变化. 第5次作业:多线程电梯 基本照搬了课件上“生产者-消费者”模型的设计策略,将InputHandler设计为生产者线程, ...
- 第二次oo博客作业--多线程电梯
这次的系列作业是写一个电梯调度,主要目的是让我们熟悉多线程. 第一次作业是一个傻瓜电梯的调度问题,要求也很简单,即每次接一个人就行了.我只用了两个线程,一个是输入线程,一个是电梯线程,输入线程负责从标 ...
- 第一次oo博客作业--表达式求导
(1)说实话我这部分真的不知道写些什么,因为我只有第三次作业写了两个类,前两次都是一个类,一个类的好处可能也就是写起来比较方便(不用抽象什么共性了,直接c语言莽过去),缺点很多,架构不清晰,可读性不高 ...
- OO博客作业
第一次多项式的作业感觉还行,同时用c和java写的话也算是一个从c到java的过渡,也算是有了对 java的初步认识,之后的电梯作业出血了一些小BUG,比如有些情况考虑不完善之类的,也算是对面向对象有 ...
随机推荐
- android studio编译包真机安装失败解决方案记录
Android studio升级到3.0之后,编译的APK文件无法在真机上安装,提示安装失败,最开始以为是API版本过高,与手机的版本不兼容,然后降低API,结果依然是安装失败. 然后连接手机,直接调 ...
- shell问题汇总
1. sudo执行脚本找不到变量 当普通用户下,设置并export一个变量,然后利用sudo执行echo命令,能得到变量的值,但是如果把echo命令写入脚本,然后再sudo执行脚本,就找不到变量,未能 ...
- HTML文本域标签
textarea文本域 cols指定列数 rows行数(不够用会自动扩容)
- git的安装方法
下载:https://git-scm.com/downloads
- HDU2020——绝对值排序(java实现,使用map)
Question Description Input Output Sample Input Sample Output 解题思路简述: 在接收每一个数组的过程中,将负数及其绝对值以键值对的形式存入m ...
- 5G套餐资费或为199元至599元,高昂价格会阻碍大众使用热情吗?
近段时间,运营商各种谜一般的操作让其走上舆论的风口浪尖,成为人们口诛笔伐的对象.比如在前段时间,运营商相继宣布要取消"达量降速版畅享套餐",对用户的权益造成巨大冲击,引发了网络热议 ...
- TNS-12545: Connect failed because target host or object does not exist
问题描述 $ lsnrctl startLSNRCTL for Linux: Version 12.1.0.2.0 - Production on 26-JUL-2017 09:53:42Copyri ...
- django 搭建一个投票类网站(一)
写在最前,之前零零散散的看过django,但是由于比较杂,学的云里雾里的,所以就停了一段落,但是我最近找到了一个django的书,是李建编著的django入门与实践,于是,打算照着书上的步骤来写好一个 ...
- 使用Limit实现分页
limit语法 #语法 SELECT * FROM table LIMIT stratIndex,pageSize SELECT * FROM table LIMIT 5,10; // 检索记录行 6 ...
- SpringBoot整合WEB开发--(四)@ControllerAdvice
1.全局异常处理: @ControllerAdvice处理全局数据,一般搭配@ExceptionHandler,@ModelAttribute以及@InitBinder使用. @ControllerA ...