ADT是对现实中事物的一种抽象,我对ADT的理解是他有两层,一个是数据层、另一个是操作层。换言之就是外界通过操作层的方法使用数据层的内容。就好比我要设计一个可以喝水的人的ADT,我需要设计一个嘴作为ADT的数据,然后在设计一个能够让嘴去喝水的方法。
我们从设计一个无向图的ADT来理解如何设计一个ADT。假设我们现在要设计一个无向图的ADT,他要能够实现创建、增删节点/边,打印图功能。
-
分析用户要求
通过分析用户要求,我们可以得到,我们设计了一款可变的ADT,需要有一个构造方法、增删节点/边的方法,打印图的方法,里面需要存储一些数据。
-
制定spec
有了对用户要求的分析,我们大致知道了要设计一个什么了。下面就是对这里面的方法一个更加准确的描述,一般来说spec是面向程序员的,你不能告诉程序员我这个方法是增加一个点,你还必须告诉他我需要哪些参数、方法最后返回什么,中间如果需要特殊情况会怎么处理。在Java中我们可以采用接口的方式来表示一个ADT的外观,并且在接口中描述ADT的spec。
-
编写测试
设计好了spec之后还没有到编写代码的时候,我们要先根据我们写好的spec的前置条件和后置条件编写测试代码,因为这是基础,ADT必须要满足正确性。通过使用的是Junit工具。代码测试分为两种,黑盒测试和白盒测试,我们是在设计完spec就编写测试,所以这里的测试用的是黑盒测试。黑盒测试有两种,笛卡尔积全覆盖和至少覆盖一次。 -
设计Rep
已经到了ADT内容的编写了,Rep就是你采用什么数据类型来抽象现实事物,比如例子中我们要抽象一个图,我们不可能在计算机中画一个图存起来。首先需要对图的属性进行分析,学过图论知道图有两个部分,点和边。我们还需要知道如何表示点、边,可以简单一点,有字符串来表示。最后用两个集合分别存储所有的点和边。这样我们的Rep就设计完了。
设计一个Rep不单单是能够表示现实事物就行了,为了提高ADT的可读性,你需要编写映射函数AF,并且要满足这个映射是满射。Rep不一定要满足单射,相反不满足单射还可以为ADT增加一些灵活性。
需要考虑的是,我们的例子中使用的是两个String的list,图中的节点是没有重复的,但是list是允许的,那么这个数据结构的范围实际上是超过了Rep需要的范围,我们需要定义一个函数checkRep,就是用来检查Rep在各种操作之后是否还能在我们需要的范围。如果不在,只能说明ADT有问题。 -
编写代码
根据前面spec,Rep开始实际编写代码。ADT的一个重要性质就是防止表示泄露,前面采用接口的方式已经取得了一定程度上的表示不泄露。但是ADT可以通过参数以及返回值与外界做交流。我们要掐断ADT和外界的一切沟通。通常采用的技术就是防御式拷贝、使用不可变数据,不可变引用。 -
运行测试
进行到了这里,ADT的开发阶段就算完成了,后面的工作就要交给大量的使用者在使用过程中发现问题,然后再对ADT进行修改。