ADT学习总结
什么是ADT
ADT——abstract data type ,即从数据结构、内存存储、具体实现方式中抽象出来,完全由操作定义的数据类型。
它存在哪些操作?
- Creators:构造器,实现方式为构造函数或静态函数。比如,
new ArrayList()
—构造函数,List.of()
—工厂方法。 - Producer:生产器,由已知的对象产生新的对象
- Observers:观察器,返回对象的属性
- Mutators:变值器,改变对象属性的方法
设计ADT
设计好的ADT,靠“经验法则”,提供一组操作,设计其行为规约 spec
- 设计简洁、一致的操作
- 支持client对数据所做的所有操作的需要,且client使用操作的难度要低
- 要么抽象、要么具体,不要混合,比如,不要在List中存在给数字排序的方法,那应该交由NumberList实现
表示独立性
表示独立性:client使用ADT时无需考虑其内部如何实现,ADT内部表示的变化不应影响外部spec和客户端
在上图中,直接访问people
属性就是违背了表示独立性,如果今后我改变了people的变量名,那么客户端就会崩溃,应该使用getMember
方法建立一个内外隔绝
不变量
一个ADT最重要的属性就是保持不变量,不变量由ADT负责,与client端的任何行为都无关
下面是一个错误示例:
Book huoZhe = new Book("Yu Hua","To live");
huoZhe.author = "Lao She";
这不仅影响不变性,也影响了表示独立性:无法在不影响客户端的情况下改变其内部表示
我们可以通过使用private
,final
标记变量来解决
另一个错误示例:
Public static Tweet retweetLater(Tweet t) {
Date d = t.getTimetamp();
d.setHours(d.getHours()+1);
return new Tweet("rbmllr", t.getText(), d);
}
这样会使client得到对象的Date属性,从而使得client可以改变其内部值,影响了不变量的原则
我么可以通过使用Defensive copying
来解决
Public Date getTimestamp() {
return new Date(timestamp.getTime());
}
当复制代价很高时,我们可以在cilent可见的spec中限定规则,但把希望寄托于client中是迫不得已的做法
RI and AF
RI:Rep Invariant 一个条件,描述了什么是合法的表示值,限定rep value(内部方法需要的合法值)
AF:Abstraction Function 对合法的表示值做出解释——每个rep value如何映射到abstract value(用户返回的值)
下面是一个示例:
小结
ADT是一个将内部操作逻辑与client隔离开的“防火墙”,使得client可以在不关心实现细节的情况下使用数据类型,这种抽象性质使得软件更易于设计、理解和维护。
ADT是一个将内部操作逻辑与client隔离开的“防火墙”,使得client可以在不关心实现细节的情况下使用数据类型,这种抽象性质使得软件更易于设计、理解和维护。