抽象数据类型 (ADT)

一、Abstraction and User-Defined Types

抽象数据类型与表示独立性:能够分离程序中数据结构的形式和对其使用的方式
ADT的特性:不变量、表示泄漏、抽象函数AF、表示不变量RI
除了编程语言所提供的基本数据类型和对象数据类型,程序员可定义自己的数据类型
数据抽象:由一组操作所刻画的数据类型
传统的类型定义:关注数据的具体表示
抽象类型:强调“作用于数据上的操作”,程序员和client无需关心数据如何具体存储的,只需设计/使用操作即可。
ADT是由操作定义的,与其内部如何实现无关。

二、Classifying Types and Operations

可变类型的对象:提供了可改变其内部数据的值的操作

不可变数据类型: 其操作不可改变内部值,而是构造新的对象

  构造器:可能实现为构造函数或静态函数
factory method 实现为静态方法的构造器通常称为工厂方法
变值器通常返回void
如果返回值为void,则必然意味着它改变了对象的某些内部状态
变值器也可能返回非空类型  
三、 Abstract Data Type Examples
1. int and String
▪ int is immutable, so it has no mutators.
– creators: the numeric literals 0 , 1 , 2 , …
– producers: arithmetic operators + , - , * , /
– observers: comparison operators == , != , < , >
– mutators: none (it’s immutable)
▪ String is Java’s string type. String is immutable.
– creators: String constructors
– producers: concat , substring , toUpperCase
– observers: length , charAt
– mutators: none
2.List( mutable)
– creators: ArrayList and
LinkedList constructors,
Collections.singletonList
– producers:
Collections.unmodifiableList
– observers: size , get
– mutators: add , remove , addAll ,
Collections.sort
四 、 Designing an Abstract Type
良好ADT的设计:靠“经验法则”,提供一组操作,设计其行为规约 spec
Rules of thumb 1 设计简洁、一致的操作
设计一组简单操作,通过简单操作的组合实现复杂的操作。操作的行为应该是内聚的。
Rules of thumb 2 要足以支持client对数据所做的所有操作需要,且用操作满足client需要的难度要低
判断方法:对象每个需要被访问到的属性是否都能够被访问到
Rules of thumb 3 要么抽象、要么具体,不要混合 --- 要么针对抽象设计,要么针对具体应用的设计
面向具体应用的类型不应包含通用方法, 面向通用的类型不应包含面向具体应用的方法。
五、 Representation Independence
表示独立性:client使用ADT时无需考虑其内部如何实现,ADT内部表示的变化不应影响外部spec和客户端。
通过前提条件和后置条件充分刻画了ADT的操作,spec规定了client和implementer之间的契约,明确了client知道可以依赖哪些内容,implementer知道可以安全更改的内容。

 

 

六、Testing an Abstract Data Type

How to test an ADT:

测试creators, producers, and mutators:调用observers来观察这些operations的结果是否满足spec;

测试observers:调用creators, producers, and mutators等方法产生或改变对象,来看结果是否正确。

风险:如果被依赖的其他方法有错误,可能导致被测试方法的测试结果失效。

 

七、Invariants

ADT需要始终保持其不变量

不变量:程序在任何时候总是true的性质。例如:immutability就是一个典型的“不变量”

由ADT来负责其不变量,与client端的任何行为无关

为什么需要不变量:保持程序的“正确性”,容易发现错误。
总是要假设client 有“恶意”破坏ADT不变量的行为---defensive programming
不仅影响不变量,也影响了表示独立性:无法在不影响客户端的情况下改变其内部表示。

To make it immutable:The private and public keywords indicate which fields and methods are accessible only within the class and which can be accessed from outside the class.The final keyword also helps by guaranteeing that the fields of this immutable type won’t be reassigned after the object is constructed.

除非迫不得已,否则不要把希望寄托于客户端上,ADT有责任保证自己的invariants,并避免“表示泄露”。最好的办法就是使用immutable的类型,彻底避免表示泄露。
保持不变性和避免表示泄漏,是ADT最重要的一个Invariant!
八、Rep Invariant and Abstraction Function
表示值构成的空间:实现者看到和使用的值
一般情况下ADT的表示比较简单,有些时候需要复杂表示
抽象值构成的空间:client看到和使用的值

 

ADT开发者关注表示空间R,client关注抽象空间A。
Mapping between R and A: 满射、未必单射、未必双射
抽象函数:R和A之间映射关系的函数,即如何将R中的每一个值解释为A中的每一个值。
AF : R → A

 

表示不变性RI:某个具体的“表示”是否是“合法的”
也可将RI看作:所有表示值的一个子集,包含了所有合法的表示值
也可将RI看作:一个条件,描述了什么是“合法”的表示值
同一个ADT,可以有多种表示;不同的内部表示,需要设计不同的AF和RI
选择某种特定的表示方式R,进而指定某个子集是“合法”的(RI),并为该子集中的每个值做出“解释”(AF)——即如何映射到抽象空间中的值。
同样的表示空间R,可以有不同的RI。
即使是同样的R、同样的RI,也可能有不同的AF,即“解释不同”。
设计ADT:(1) 选择R和A;(2) RI --- 合法的表示值;(3) 如何解释合法的表示值 ---映射AF
做出具体的解释:每个rep value如何映射到abstract value,而且要把这种选择和解释明确写到代码当中。
Checking the Rep Invariant 随时检查 RI是否满足: 在所有可能改变rep的方法内都要检查,Observer方法可以不用,但建议也要检查,以防止你的“万一”。
九、 Beneficent mutation
对immutable的ADT来说,它在A空间的abstract value应是不变的。但其内部表示的R空间中的取值则可以是变化的。
这种mutation只是改变了R值,并未改变A值,对client来说是immutable的 →“AF并非单射”,从一个R值变成了另一个R值。此种可变是无害的,甚至是有益的。但这并不代表在immutable的类中就可以随意出现mutator!
十、Documenting the AF, RI, and Safety from Rep Exposure
在代码中用注释形式记录AF和RI ;要精确的记录RI:rep中的所有fields何为有效;要精确记录AF:如何解释每一个R值 ;表示泄漏的安全声明;给出理由,证明代码并未对外泄露其内部表示——自证清白。

 

 

十一、ADT invariants replace preconditions

用ADT不变量取代复杂的Precondition,相当于将复杂的precondition封装到了ADT内部。
  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值