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之卷》的更多相关文章

  1. OO博客作业1:第1-3周作业总结

    (1)基于度量来分析自己的程序结构 注:UML图中每个划分了的圆角矩形代表一个类或接口,箭头可代表创建.访问数据等行为.类的图形内部分为3个部分,从上到下依次是类的名称.类包含的实例变量(属性).类实 ...

  2. OO博客作业3:第9-11周作业总结

    一.总结介绍规格化设计的大致发展历史和为什么得到了人们的重视 1.规格化设计的大致发展历史 规格化设计,又称契约式设计,最早由Bertrand Meyer于1986年提出,出自于<面向对象软件构 ...

  3. BUAA_OO第三单元总结性博客作业——JML

    一.JML 在第三单元的面向对象课程中我们第一次接触了JML语言以及基于JML规范的规格化设计.在之前一系列关于面向对象思想的学习认识中,我们知道了Java是一种面向对象的语言,面向对象思想的一个重要 ...

  4. 第四次oo博客作业

    (1)本单元是撰写UML数据分析器,架构大致如下,在指导书要求的函数外,对于UmlClass类,Umlinterface类,以及状态机,顺序图这四个类重现构造一个类,这个类里有他们所需要的全部信息,另 ...

  5. OO博客作业4:第13-14周作业总结

    一.论述测试与正确性论证的效果差异,比较其优缺点 测试是设计若干组测试用例,运行程序并检验其是否完成预期功能.测试是一种直接发现BUG的方法,可以准确断定什么样的BUG会发生,并通过辅助调试进一步确定 ...

  6. OO博客作业2:第5-7周作业总结

    (1)从多线程的协同和同步控制方面,分析和总结自己三次作业来的设计策略及其变化. 第5次作业:多线程电梯 基本照搬了课件上“生产者-消费者”模型的设计策略,将InputHandler设计为生产者线程, ...

  7. 第二次oo博客作业--多线程电梯

    这次的系列作业是写一个电梯调度,主要目的是让我们熟悉多线程. 第一次作业是一个傻瓜电梯的调度问题,要求也很简单,即每次接一个人就行了.我只用了两个线程,一个是输入线程,一个是电梯线程,输入线程负责从标 ...

  8. 第一次oo博客作业--表达式求导

    (1)说实话我这部分真的不知道写些什么,因为我只有第三次作业写了两个类,前两次都是一个类,一个类的好处可能也就是写起来比较方便(不用抽象什么共性了,直接c语言莽过去),缺点很多,架构不清晰,可读性不高 ...

  9. OO博客作业

    第一次多项式的作业感觉还行,同时用c和java写的话也算是一个从c到java的过渡,也算是有了对 java的初步认识,之后的电梯作业出血了一些小BUG,比如有些情况考虑不完善之类的,也算是对面向对象有 ...

随机推荐

  1. IDEA模板注释及相关快捷键设置

    IDEA模板注释及相关快捷键设置 最近使用IDEA时发现自带的模板注释不怎么好用,因此自己根据网上的教程总结了适合自己的模板设置,可以一键生成类和方法的注释,废话不多说一起看看吧: 第9步的类模板注释 ...

  2. C++——动态内存分配1

    9.动态内存分配  new 类型名T(初值列表) 其功能是在程序执行期间申请用于存放T类型对象的内存空间,并依初值列表赋以初值,结果值:成功则T类型的指针,指向新分配的内存:失败则为0(null).若 ...

  3. opencv图像坐标

    原图: 尺寸:240 × 150 灰度化: 1. 程序中输出像素点的灰度值: 2. 用工具取得的灰度值: 按照如下的坐标(图像处理坐标系) 得到的灰度值: (35,82) (82,35) 换算后分别是 ...

  4. Three.js的开始(附代码)_2

    1 下载Three.js代码 https://github.com/mrdoob/three.js/tree/master/build 2 引用方法 在HTML中添加以下代码: <script ...

  5. 支持CSS3的高级CSS

    一.匹配部分字符串 在CSS2中,可以使用[ href='info.htm' ] 这样的属性选择器来匹配href属性中的字符,但是无法只匹配部分字符串.而CSS3给出了三个新的运算符:^ , $ 和 ...

  6. 一、c++语言基础

    1. 程序员的第一条代码"Hello,world!" #include <cstdio> //头文件,主要负责输入.输出 using namespace std;//C ...

  7. 安装python包时遇到"error: Microsoft Visual C++ 9.0 is required"的简答(Python2.7)

    简答 在Windows下用pip安装Scrapy报如下错误, error: Microsoft Visual C++ 9.0 is required (Unable to find vcvarsall ...

  8. vscode+vue 一些基本操作

    1.安装好 vscode 和 node.js 安装node.js是为了用npm(管理项目依赖) 2.调出终端 crtl +~ , 3.终端全局安装 vue-cli  安装整个脚手架,能快速给我们构建v ...

  9. [P4549] 【模板】裴蜀定理 - GCD

    __gcd真好用 #include <bits/stdc++.h> using namespace std; int main() { int n,x,a=0; cin>>n; ...

  10. C++-main函数与命令行参数

    1.main函数的概念 C语言中main函数称之为主函数 —个C程序是从main函数开始执行的 下面的main函数定义正确吗? //1 main(){ } //2 void main(){ } //3 ...