文章目录
抽象数据类型 (ADT)
1 ADT操作的四种类型
-
四种类型
-
creator:(从无到有)构造器,创建该类型的新对象,
- 如
String.valueOf(Object Obj)
- 可能实现为构造函数、静态函数
- 如
-
producer:(从有到新)生产器,从该类型的旧对象创建新对象
- 如
String.concat()
方法
- 如
-
observer:观察器,获取抽象类型的对象并返回不同类型的对象
- 如
.size()
- 如
-
mutator: 变值器,只有可变数据类型才有,是改变对象属性的方法,
- 如
list.add()
、StringBuilder .append()
- 变值器通常返回
void
,意味着它改变了对象的某些内部状态
- 如
-
-
举例
- String is immutable.
- creators:
String constructors
- producers:
concat
,substring
,toUpperCase
- observers:
length
,charAt
- mutators: none
- creators:
- List is mutable
- creators:
ArrayList
andLinkedList constructors
,Collections.singletonList
- producers:
Collections.unmodifiableList
- observers:
size
,get
- mutators:
add
,remove
,addAll
,Collections.sort
- creators:
2 表示独立性、表示泄露
-
表示独立性(Representation Independence):
client使用ADT时无需考虑其内部如何实现,ADT内部表示的变化不应影响外部spec和客户端,程序员具有自己的自由。 -
表示泄漏
用户以某种方式可以看到内部结构,或者用户的一些操作会影响到内部表示。内部的成员变量、操作都不可以让用户看到。 -
如何防止表示泄漏:
- 将
public
变为private
(防止外部修改) - 使用
final
关键字(防止内部修改) - 在规约中强调说明(不是个好的方案)
- 最好的方法是使用
不可变类型
,彻底避免表示泄漏
- 将
3 不变量、表示不变量RI
- 不变量
是程序的一种属性,与客户端操作无关,对于程序的每个可能的运行时状态,它都始终为真。不变量包括表示不变量和避免表示泄漏。 - 表示不变量RI(
Rep Invariant
)
是一个重要的ADT不变量,判断某个具体的表示是否是合法(规约)的;也可以看作所有表示值的一个子集,包含了所有合法的表示值;也可看作一个条件,描述了什么是”合法“的表示值
4 表示空间、抽象空间、AF
-
表示空间:以R表示,是开发者看到和使用的值
-
抽象空间:以A表示,是用户看到和使用到的值
-
两个空间是满射关系(每个抽象值都被某个表示值映射到,即用户的可选项一定在开发者的适用范围内),但未必是单射,也未必双射
-
抽象函数AF:R和A之间的关系,即如何将R中的每一个值解释为A中的每一个值,在图中用箭头表示(将代码中用到的变量映射成逻辑需要的值)
5 以注释的形式撰写AF、RI
-
规则:
-
AF和RI应该写到注释中,不能写到JavaDoc中,即,不可以将具体实现泄漏给用户,用户不能知道具体实现方法,也不能对某个具体类的成员变量(属性、字段)或者实现(方法)进行修改
-
对于RI来说,像“所有字段都有效”这样的泛型语句是不够的,RI的工作是精确解释字段值有效与否的原因。
-
AF 提供“表示一组字符”这样的通用解释是不够的,要精确记录AF:如何解释每一个R值
-
-
举例
*6 设计ADT
(1) 选择R和A;
(2) RI — 合法的表示值;
(3) 如何解释合法的表示值 —映射AF,做出具体的解释:每个rep value如何映射到abstract value
*7 checkRep()
- asserts the rep invariant at run time
- 在所有可能改变rep的方法内都要检查
- Observer方法可以不用,但建议也要检查,以防止你的“万一”