抽象数据类型 (ADT)
目 录
- 抽象类型和用户定义的类型
- 抽象类型:
强调“作用于数据上的操作”,程序员和client无需关心数据如何具体存储的,只需设计/使用操作即可。ADT是由操作定义的,与其内部如何实现无关!
(2)用户定义:除了编程语言所提供的基本数据类型和对象数据类型,程序员可定义自己的数据类型。
- 对类型和操作进行分类
- 可变类型:提供了一些操作,执行这些操作会导致同一对象上的其他操作的结果产生不同的结果。
- 不可变类型:其操作不改变内部值,而是构造新的对象。
- 抽象类型的操作:
Creators:构造器,创建该类型的新对象,创建者可以将对象作为参数,但不能将其作为正在构造的类型的对象。可能实现为构造函数或静态函数(工厂方法)
Producers:生产器,从该类型的旧对象中创建新对象。
Observers:观察器,获取抽象类型的对象,并返回不同类型的对象。
Mutators:变值器,改变对象属性的方法,通常返回void,或返回boolean等非空类型
- 抽象数据类型示例
- 抽象类型设计
- 少而精的操作,目的明确,行为连贯
- 要足以支持client对数据所做的所有操作需要,且用操作满足client需要的难度要低
- 要么抽象、要么具体,不要混合 --- 要么针对抽象设计,要么针对具体应用的设计。
- 表示独立性
- Representation Independence表示独立性:client使用ADT时无需考虑其内部如何实现,ADT内部表示的变化不应影响外部spec和客户端。除非ADT的操作指明了具体的pre-和post-condition,否则不能改变ADT的内部表示——spec规定了client和implementer之间的契约。
- 测试抽象数据类型
- 如何测试ADT:为ADT的每个操作创建测试。
测试creators, producers, and mutators:调用observers来观察这些operations的结果是否满足spec;
测试observers:调用creators, producers, and mutators等方法产生或改变对象,来看结果是否正确。
- 不变量
- 保持不变量invariants:不变性是一个关键的不变量:一旦创建,不可变对象应该在其整个生命周期中始终代表相同的值。由ADT来负责其不变量,与client端的任何行为无关。
- 为什么要保持不变量:保持程序的“正确性”,容易发现错误,总是要假设client有“恶意”破坏ADT的不变量---defensive programming(有意或无意)
- 表示泄露rep exposure: 不仅影响不变性,也影响了表示独立性:无法在不影响客户端的情况下改变其内部表示。
- 使用private和public关键字表示哪些字段和方法只能在类内访问,哪些可以从类外部访问。final关键字还可以确保在构造对象后不会重新分配此不可变类型的字段。
- 防御性复制Defensive copying:我们可以通过使用防御性复制来修复这种表示泄漏:制作一个可变对象的副本,以避免泄漏对表示方法的引用。复制可变对象的另一种方法是clone(),某些类型支持,但不是全部支持。
- 最好的办法就是使用immutable的类型,彻底避免表示泄露。
- 表示不变性和抽象函数
R:表示空间,表示值(代表值)的空间由实际实现实体的值组成
A:抽象值构成的空间:client看到和使用的值
ADT开发者关注表示空间R,client关注抽象空间A
- Rep Invariant表示不变性:
RI告诉我们空间R中的r是否被AF映射到了空间A中的某个值,RI形成了空间R的一个子集(子集中的所有元素均被AF映射到了空间A中)
- Abstraction Function抽象函数:
R和A之间映射关系的函数,即如何去解释R中的每一个值为A中的每一个值。
- 相同的R可能有不同的RI,即使是同样的R、同样的RI,也可能有不同的AF,即“解释不同”。
- RI和AF设计ADT
设计ADT:(1) 选择R和A;(2) RI --- 合法的表示值;(3) 如何解释合法的表示值 ---映射AF
- 检查RI
- 有益的可变性
- 抽象值永远不应该改变,对immutable的ADT来说,它在A空间的abstract value应是不变的。
- 有益的可变性:实现方法是可以自由更改表示值的,只要它继续映射到相同的抽象值,那么客户端就不知道这种更改,但其内部表示的R空间中的取值则可以是变化的。
- 这种mutation只是改变了R值,并未改变A值,对client来说是immutable的 à“AF并非单射”,从一个R值变成了另一个R值
- 记录AF、RI、以及表示泄露的安全性
- 在代码中用注释形式记录AF和RI,要精确的记录RI:rep中的所有fields何为有效要精确记录AF:如何解释每一个R 值。
- rep exposure safety argument表示泄漏的安全声明:给出理由,证明代码并未对外泄露其内部表示——自证清白