软件构造3.3 ADT

3.3 ADT
1、抽象数据类型与表示独立性:如何设计良好的抽象数据结构,通过封装来避免客户端获取数据的内部表示(即“表示泄露”),避免潜在 的bug——在client和imp;
2、 ADT的特性:不变量、表示泄漏、抽象函数AF、表示不变量RI;
3、抽象类型:强调“作用于数据上的操作”,程序员和client无需关心数据如何具体存储的,只需设计/使用操作即可。ADT是由操作定义的,与其内部如何实现无关!
ADT操作的四种类型
  • Creators构造器 可能实现为构造函数或静态函数
  • Producers 生产器
  • Obsrrves 观察器
  • Mutators 变值器 改变对象属性的方法; 变值器通常返回void,一旦返回void,则必然意
味着它改变了对象的某些内部状态;也可能返回非空类型。

例子:


表示独立性
表示独立性:client使用ADT时无需考虑其内部如何实现,ADT内部表示的变化不应影响外部spec和客户端。
除非ADT的操作指明了具体的pre-condition和post-condition,否则不能改变ADT的内部表示——spec规定了client和implementer之间的契约

避免泄露、表示不变量RI
保持不变量invariants。不变量:在任何时候总是true; 由ADT来负责其不变量,与client端的任何行为无关;
最好的方法是使用不变型immutability。下面给出一个例子:
没有规定timestamp是否可变导致泄露。这样一来,不仅影响不变性,也影响了表示独立性:无法在不影响客户端的情况下改变其内部表示。
进行如下修改:private和final的限定

但是由于Data是可变的,可能会产生这样的错误
只好进行防御式拷贝对Data进行修改
但我们在创建Tweet对象前可能引用过Data,那只能进行一次次的防御式拷贝。如果拷贝代价过大,还要在spec中把责任推给客户端,引发更多的Bug。
综上,最好的方法就是直接使用immutable的类型,彻底避免泄露。

表示空间、抽象空间、AF
表示空间R:实际表示值所构成的空间。ADT实现者关注表示空间R;
抽象空间A:抽象值所构成的空间,client看到和使用的值。用户关注抽象空间A。
抽象函数AF:R和A之间映射关系的函数。
AF:R--->A
这个映射是满射但未必单射;
表示不变性RI:

以注释的形式撰写AF、RI
  1. 不同的内部表示,需要设计不同的AF和RI
  2. 选择某种特定的表示方式R,进而指定某个子集是“合法”的(RI),并为该子集中的每个值做出“解释”(AF)——即如何映射到抽象空间中的值
  3. 即使是同样的R、同样的RI,也可能有不同的AF,即“解释不同”。
4. 在代码中用注释形式记录AF和RI和表示泄露的安全声明
注意:(spec和注释)
  1. ADT的规约里只能使用client可见的内容来撰写,包括参数、返回值、异常等
  2. 如果规约里需要提及“值”,只能使用A空间中的“值”
  3. ADT的规约里也不应谈及任何内部表示的细节,以及R空间中的任何值;ADT的内部表示(私有属性)对外部都应严格不可见,故在代码中以注释的形式写出AF和RI而不能在Javadoc文档中,防止被外部看到而破坏表示独立性/信息隐藏

猜你喜欢

转载自blog.csdn.net/qq_41406742/article/details/80777538
ADT