ADP + OOP
五、抽象数据类型(ADT)
阅读资料:
MIT 课程阅读10-抽象数据类型
MIT 课程阅读11-抽象函数与表示不变量
1、抽象和用户定义的类型
除了编程语言提供的基本数据类型和对象数据类型,程序员可以定义自己的数据类型。
数据抽象:由一组操作所刻画的数据类型
传统的类型:关注数据的具体表示
抽象数据类型强调作用在数据上的操作,程序员和客户端只需设计/使用操作,不需要关心数据如何具体存储。
2、类型和操作的分类
类型可分为可变和不可变数据类型两种。
-
可变类型的对象提供了可改变其内部数据的值的操作
-
不变类型的对象的操作不改变内部值,而是构造新的对象
抽象类型的操作分类
构造器creators:创建一个该类型的新对象,可能实现为构造函数或静态函数
生产器producers:通过接受同类型的对象创建新的对象
观察器observer:接受一个同类型的对象,返回一个不同类型的对象/值
变值器mutators:改变对象的内容,通常返回void
,也可能返回空类型
3、抽象数据类型例子
int
是不可变类型,没有变值器
creators:0
,1
,2
…等数字
producers:算数符+
,-
,*
,/
observer:比较符号==
,!=
,<
,>
mutators:无
4、设计抽象类型
- 设计简洁、少量、一致的操作,组合可实现强大功能
- 操作充分考虑客户的需求,支持用户的所有可能的计算
5、表示独立性 Representation Independence
表示独立性:客户使用ADT时不需要考虑内部的实现,ADT内部的变化不会影响外部规约(spec)和客户端
6、测试抽象数据类型
-
调用observers来测试creators,producers,和mutators,观察结果是否满足规约spec
-
调用creators,producers,和mutators来产生或改变对象,查看结果测试observers是否正确
风险:如果被依赖的方法有错误,可能导致被测试的方法测试结果失效
7、不变量 Invariants
好的ADT会保护自己的不变量。
不变量是一种属性,在程序运行时总是一种状态,不变性是其中的一种
表示泄露:类外部代码可以直接修改内部存储的数据。
Tweet t = new Tweet("justinbieber","Thanks",new Date());
t.author = "rbmllr";
不仅影响不变性,也影响了表示独立性:无法在不影响客户端的情况下改变其内部表示。
处理表示泄露:
public class Tweet{
private final String author;
private final String text;
private final Date timestamp;
public Tweet(String author,String text,Date time){
this.author = author;
this.text = text;
this.timestamp = time;
}
public String getAuthor(){
return author;
}
public String getText(){
return text;
}
public String getTimestamp(){
return timstamp;
}
}
8、表示不变量和抽象函数
表示空间:包含值具体的实现实体
抽象空间:包含的是类型设计时支持使用的值,这些值由表示空间抽象出来,客户端看到和使用的值
开发者关注表示空间R,客户端关注抽象空间A
抽象函数AF:abstraction function表示值到其对应的抽象值的映射,满射非单射
表示不变量RI:rep invariant表示值到布尔值的映射,某个具体的表示是否合法;可看做表示值得一个子集,包含所有合法的表示值,或一个条件描述什么是合法的表示值
public class CharSet{
private String s;
// Rep invariant:
// s.lenth() is even
// s[0] <= s[1] <= ... <= s[s.length() - 1]
// Abstraction function:
// AF(s) = union of {s[2i],...,s[2i + 1]} for 0 <= i < s.length()/2
...
}
9、有益的改变
对于不可变的ADT,它在抽象空间的抽象值是不变的,但它内部表示的表示空间中的取值可以变化
10、AF,RI以及表示泄露安全性的注释
在代码中用注释的形式记录AF和RI
精确记录RI(表示不变量):明确说明什么是合法的/不合法的
精确记录AF(抽象函数):解释每一个抽象值
表示泄露的安全声明:说明为什么不会发生表示泄露
//Abstraction function:
// AF(labelSet) = 标签的集合
// AF(IntervalSet) = 各标签对应时间段的集合
// Representation invariant:
// labelSet中包含所有IntervalSet中的key
// Safety from rep exposure:
// 设置labelSet 和 IntervalSet为final