1.ADT的优势
我们在编程过程中,会用到各种各样的数据类型来表示和存放我们需要的数据,各种编程语言也往往会给出一些基本数据类型,比如常见的int类型、float类型、boolean类型等,当然编程语言也为我们提供了创造自己所需的更加复杂的数据类型的方法,比如C语言中的结构体就允许我们用各种基本数据类型来定义自己的数据类型,从而使之与现实生活形成一个映射。
但是回想这样的数据类型,数据的表示与对数据的操作是相分离的,任何人使用该数据结构时都要熟悉数据类型的内部组成才有可能对其进行操作。这显然不利于大型项目的开发,同时也存在着数据泄露的安全性风险。
抽象数据类型则基于操作来刻画数据类型,将数据类型的内部组成封装在内部,仅仅将对数据的操作暴露给操作者,既保证了数据的安全,同时也降低了数据类型的使用成本,提高了团队开发的效率。抽象数据类型强调“作用于数据上的操作”,程序猿和client无需关心数据如何具体储存,只需设计和使用操作即可。
2.抽象数据类型的两种类型和操作的四种分类
抽象数据类型有两种类型:可变数据类型和不可变数据类型。
可变数据类型:操作可以改变对象内部储存的数据值。
不可变数据类型:其操作则不能改变其内部值,一旦有要想改变内部值的操作就会返回一个新的对象,从而保证原对象的值不被改变。
操作部分大致可以分为四类:
构造器:可以是类的构造函数也可以是静态方法(工厂方法);
生产器:利用原有的对象生成新的对象出来;
观察器:取得该数据类型的对象内部的一些值;
变值器:改变对象内部的数据的值,通常变值器返回void值,但有时为了连续操作的方便会返回对象本身。
在这里需要注意的是,观察器返回的内容应当是没有内部数据暴露的,与结构中的数据应当没有直接关联,也就是说,通过改变观察器返回的内容不能导致原对象中的内部数据遭到篡改,否则将会发生难以想象的错误,为此观察器返回的值如果是mutable类型,应当返回一个全新的拷贝,当然如果返回的值为immutable类型则可以之间返回。
3.ADT设计中的规约
规约可以理解为开发者和用户之间的契约,开发者根据规约对ADT进行设计,只要实现了规约的要求即可(因此ADT可以有不同的实现),而用户根据规约来对开发好的ADT进行操作,无需得知其具体实现。规约作为开发者和用户之间的界限,将开发者和用户区分开,起到了解耦合的作用,明确了二者的责任划分,起到十分重要的作用。
4.ADT中的重要概念:RI,AF,Safety from Rep Exposure
RI:Rep Invariant 表示不变量
-
表示不变量可以理解为整个ADT的固有属性,一旦有的对象中的表示违背了表示不变量,将会影响到该ADT的正确性,因此ADT提供的操作绝对不可以破坏RI,比如我们有一个用来表示正方形的ADT,那么长宽相等就是RI中的一部分,如果有方法能够将长或者宽改变,使二者不同,我们说这个操作就违背了RI,同样也会使该ADT没有意义。所以再设计ADT的时候应当检查不变量,再每一个操作返回前检查一下该操作确保其没有将RI破坏。
AF:Abstraction Function 抽象函数
-
抽象函数是对合法的表示值的解释,是ADT内部的数据与其要表示的抽象内容的映射。可以说ADT中的数据本身是没有意义的,只有经过了解释才能够被理解。AF的作用就是解释ADT的抽象含义。
-
注:同样的R和RI可能有不同的AF,比如R中只有一个简单的整形变量a,RI均为a>0,但是AF可以将这个ADT解释为一个人的年龄,也可以将其解释为一个人的体重,这也说明了一个道理——数据本身只是数据,没有意义,是解释让它有了意义。
Safety from Rep Exposure:表示泄露的安全声明
-
表示泄露的安全声明,说明了所有可能有表示泄露的位置的处理方法,用来证明该ADT并没有对外泄露其内部表示,换句话说,“自证清白”。