软件构造:3-3 Abstract Data Type (ADT)

抽象数据类型

ADT的特性:表示泄露,抽象函数AF,表示不变量RI

  1. 抽象以及用户定义的类型
    抽象数据类型是软件工程中一个通用原则的实例,它有很多名字:
  2. 抽象:用更简单、更高层次的思想忽略或隐藏底层细节。(规约是一种客户端只需要理解千前置和后置条件来使用的抽象,不需要了解内部实现)
  3. 模块性:将一个系统划分为各个组件或模块,可以设计、实现、测试、推理和重用与系统的其他部分分开。(单元测试和规约使得方法变为模块)
  4. 封装:围绕模块建造防护,这样模块就负责它自己的内部行为和bug在系统的其他部分不能破坏其完整性。
  5. 信息隐藏:隐藏模块实现的详细信息系统的其余部分,以便以后可以更改这些细节而不改变系统的其他部分。(规约实用信息隐藏来给与实现部分实现方法的自由)
  6. 功能分离:让每个功能只由一个模块负责而不是将其分散到多个模块中。()

ADT是由操作定义的,与其内部如何实现无关。

  1. 分类操作和类型

软件构造:3-3 Abstract Data Type (ADT)_第1张图片

操作器通常为构造函数或静态函数(工厂方法)
变值器通常返回void,也可能返回非空类型比如boolean

  1. 设计一套好的规约
    (1) 设计简洁、一致的操作
    (2) 要足以支持client对数据所做的所有操作需要,且用操作满足client需要的难度要低
    (3) 要么抽象、要么具体,不要混合 — 要么针对抽象设计,要么针对具体应用的设计

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

  3. 测试ADT
    测试creators, producers, and mutators:调用observers来观察这些operations的结果是否满足spec;
    测试observers:调用creators, producers, and mutators等方法产生或改变对象,来看结果是否正确。

  4. 不变量Invariants
    好的ADT在任何时候都要保持不变量。
    由ADT来负责其不变量,与client端的任何行为无关。
    保持不变量的原因:保持程序的正确性,容易发现错误。
    表示泄露的危害:不仅影响不变性,也影响了表示独立性:无法在不影响客户端的情况下改变其内部表示。
    除非迫不得已,否则不要把希望寄托于客户端上,ADT有责任保证自己的invariants,并避免表示泄露。
    防止表示泄露:最好的办法就是使用immutable的类型,彻底避免表示泄露。其次是防御性拷贝等。

  5. 表示不变量和抽象函数(RI和AF)
    表示空间:内部真实实现的实体。
    抽象空间:客户端看到和使用的值。

ADT开发者关注表示空间R,client关注抽象空间。

表示空间到抽象空间的映射关系如下:
满射、未必单射、未必双射。

抽象函数AF即描述表示空间和抽象空间关系的函数。

表示不变性可以看做:

  1. 某个具体的“表示”是否是“合法的”;
  2. 所有表示值的一个子集,包含了所有合法的表示值;
  3. 一个条件,描述了什么是“合法”的表示值。

选择某种特定的表示方式R,进而指定某个子集是“合法”的(RI),并为该子集中的每个值做出“解释”(AF)——即如何映射到抽象空间中的值。

即使是同样的R、同样的RI,也可能有不同的AF,即“解释不同”。

设计ADT:
(1) 选择R和A;
(2) RI — 合法的表示值;
(3) 如何解释合法的表示值 —映射AF,做出具体的解释:每个rep value如何映射到abstract value。

checkRep:
在所有可能改变rep的方法内都要检查;
Observer方法可以不用,但建议也要检查。

程序员之间的“潜规则”:数据都“非空”;

  1. 有益的可变性
    在表示空间与抽象空间的映射关系不变的前提下,ADT内部实现是可以改变rep的值,这种变化对客户端是不可见的,这种变化成为有益的可变性。

对immutable的ADT来说,它在A空间的abstract value应是不变的。
但其内部表示的R空间中的取值则可以是变化的。

  1. 规约撰写
    ADT的规约里只能使用client可见的内容来撰写,包括参数、返回值、异常等。

如果规约里需要提及“值”,只能使用抽象空间中的“值”。

ADT的规约里也不应谈及任何内部表示的细节,以及表示空间中的任何值。
ADT的内部表示(私有属性)对外部都应严格不可见。
故在代码中以注释的形式写出AF和RI而不能在Javadoc文档中,防止被外部看到而破坏表示独立性/信息隐藏。

检查ADT保持不变量的标准:

  1. 由creators和producers构造;
  2. 由mutators和observers保持;
  3. 没有表示泄露的发生。
  4. 由ADT不变量来替换前置条件
    用ADT不变量取代复杂的Precondition,相当于将复杂的precondition封装到了ADT内部。

你可能感兴趣的:(软件构造)