BUAAOO规格作业总结

一,对于这几次作业的概述

  这几次作业中我们主要是实现以及不断继承了两个对应的类,分别是一个基础的容器类,还有一个是对于整体的基础类的容器。基础的容器类在几次作业的过程之中一直是没有什么较大的变化,但是对于容器类就是不断会有不同的新的需求加入,需要不断进行架构的修改。

  初始的设计没有涉及到一些较为复杂的算法,只是提供出了一些对应的设计方法来完成简单的对应数据的查询,并且是对于Path和PathContainer类别进行了较为简单的封装。当时遇到的困难主要就是在于一些较为复杂的方法的构思以及减少复杂度的方面,很多的查询的方法其实可以依靠着在加入过程之中的保存来进行实现从而减少多次查询时候产生的复杂度。

  也是在后面PathContainer部分的时间复杂度上面进行了相关的联想以及思考,像是很多奇奇怪怪的数据都可以一次性地做出很多无用的工作从而导致程序的运行时间超时。也是在数据结构的部分进行了对应的优化,多使用了一个HashMap来存放Path的数据从而保证了减少对应的时间复杂度,但是也是增加了较为复杂的数据结构的使用次数。

  之后的设计就是主要关注于算法的实施了,因为对于最短路径的查询的时候总是会有各种程度的复杂度可以进行对应的优化,所以最后采用的是设计一个对应的最短路径矩阵的方式来对于最短路径的长度进行储存,同时在对于路径是否存在的问题上面,也是采取的相同的最短路径的矩阵进行了搜索,如果是路径的长度大于某一个固定值的话,那么就是会判定为两者之间不是连通的。

  当然还有数据结构的选择部分,因为后面的构建的过程较为复杂化,所以是使用了更加复杂一些的数据结构来进行了设计。

二,JML语言的理论基础

  关于什么是JML:JML语言是对于Java程序进行规格化设计的一种表示语言。

  同时JML是一种行为接口的规格语言,基于Larch方法进行创建。BISL提供了对于方法和类型规格的定义手段。

  关于JML的知识:

  1. 注释结构

  JML表示规格的内容包含在注释之中。可以使用行注释和块注释。行注释的表示方式为 //@annotation ,块注释的方式为 /* @ annotation @*/ 。

  2. JML表达式

  JML表达式是在基于JAVA语法基础上,新增了一些操作符和和原子表达式组成的。

  2.1 原子表达式

  \result表达式:表示方法执行后的返回值。

  \old( expr )表达式:用来表示一个表达式 expr 在相应方法执行前的取值。

  \not_assigned(x,y,...)表达式:用来表示括号中的变量是否在方法执行过程中被赋值。

  \not_modified(x,y,...)表达式:与上面的\not_assigned表达式类似,该表达式限制括号中的变量在方法执行期间的取 值未发生变化。

  \nonnullelements( container )表达式:表示 container 对象中存储的对象不会有 null。

  \type(type)表达式:返回类型type对应的类型(Class)。

  \typeof(expr)表达式:该表达式返回expr对应的准确类型。

  2.2 量化表达式

  \forall表达式:全称量词修饰的表达式,表示对于给定范围内的元素,每个元素都满足相应的约束。

  \exists表达式:存在量词修饰的表达式,表示对于给定范围内的元素,存在某个元素满足相应的约束。

  \sum表达式:返回给定范围内的表达式的和。

  \product表达式:返回给定范围内的表达式的连乘结果。

  \max表达式:返回给定范围内的表达式的最大值。

  \min表达式:返回给定范围内的表达式的最小值。

  \num_of表达式:返回指定变量中满足相应条件的取值个数。

   2.3 集合表达式

  集合构造表达式:可以在JML规格中构造一个局部的集合(容器),明确集合中可以包含的元素。 

  2.4 操作符

  (1) 子类型关系操作符: E1<:E2 ,如果类型E1是类型E2的子类型(sub type),则该表达式的结果为真,否则为假。

  (2) 等价关系操作符: b_expr1<==>b_expr2 或者 b_expr1<=!=>b_expr2 ,其中b_expr1和b_expr2都是布尔表达 式,这两个表达式的意思是 b_expr1==b_expr2 或者 b_expr1!=b_expr2 。

  (3) 推理操作符: b_expr1==>b_expr2 或者 b_expr2<==b_expr1 。对于表达式 b_expr1==>b_expr2 而言,当 b_expr1==false ,或者 b_expr1==true 且 b_expr2==true 时,整个表达式的值为 true

  3. 方法规格

  前置条件(pre-condition):前置条件通过requires子句来表示: requires P; 。其中requires是JML关键词,表达的意思是“要求调用者确保P为 真”。

  后置条件(post-condition):后置条件通过ensures子句来表示: ensures P; 。其中ensures是JML关键词,表达的意思是“方法实现者确保方法执 行返回结果一定满足谓词P的要求,即确保P为真”。

  副作用范围限定(side-effects):副作用指方法在执行过程中会修改对象的属性数据或者类的静态成员数据,从而给后续方法的执行带来影响。从方法 规格的角度,必须要明确给出副作用范围。

  4. 类型规格

  类型规格指针对Java程序中定义的数据类型所设计的限制规则。

  不变式invariant:不变式(invariant)是要求在所有可见状态下都必须满足的特性。

  状态变化约束constraint:对前序可见状态和当前可见状态的关系进行约束。

三,应用工具链情况

  openjml:jml语法的静态检查

  jmlunitng:构造测试样例等

四,架构设计以及重构分析

  第一次作业

   设计的方面并不是很多,因为很多的其实就是简单的查询的方法,所以很容易一些就可以完成,但是有些方法如果是稍微不加注意就会出现很高的时间复杂度,就像是NodeCount方法,如果是每一次都对于内部的不同的节点个数进行计算的话,之后很容易就会有爆掉时间限制的危险,同时,不止如此,如果是采取了错误的需求进行遍历的数据结构的话,也是会有后面的数据量增多时候的时间复杂度增多导致数据爆炸的可能性质。

  后面修改的过程中就是重新使用了双HashMap来对于数据重新进行了组织,以及使用了更加适合的查找的方式。

  第二次作业

 

  设计的过程之中没有考虑到后面的兼容的性质,所以就直接导致了很多的不必要的方法的出现,但是思路就是根据这些方法来一步步进行节点的添加,通过一个个的函数的调用来完成最后的实现的目的。

五,bug以及修复

  更多的bug还是存在于设计的方面,因为有的方法都是没有考虑到特定的条件下的时间复杂度的问题,所以最后出现了很多CTL的情况。具体的比如第一次作业,使用了一个ArrayList来对于不同的节点进行了存放,这就是导致了没能够直接降低在ArrayList之中一次次降低时间复杂度的方式,很多的重复的元素的堆积导致的后面当一个对应Path增多的时候的时间复杂度爆炸。

  之后的设计就尽量考虑到了遍历所带来的特定的损失,就像是使用HashMap来对于ArrayList进行替代,从而帮助整体减少重复的便利的情况,同时查询起来也是变得更加简单。再比如有些时候可以使用两个HashMap来减少对于Contain方法的遍历。

六,心得体会

  通过对于规格设计作业的一次次设计以及重构,也是认识到了很难在最初就得到自己最想要的以及那些最合适的设计,后面的设计实现的过程之中才发现之前的设计的过程之中的存在的问题以及可以改变的方面。尤其是在一次次对于需求的增加的过程之中,很难在一开始就预料到对应的设计要求。

  同时对于规格以及方法进行一次次重新书写的过程之中也是明白了在初始设计的过程之中也应该是尽量考虑到后面的条件,即使是没有办法直接对于后面的需求进行预先的判断,但是如果是可以在一开始的过程之中就判断出后面的可能的设计的话,在后面更改需求的时候,就会方便很多。

猜你喜欢

转载自www.cnblogs.com/hsc503680421/p/10905790.html
今日推荐