软件构造复习第三章3.3

抽象数据类型(ADT)

避免客户端获取数据的内部表示 (表示泄露)

  • 特征
    • 不变量
    • 表示泄露
    • 抽象函数AF
    • 表示不变量RI
  • 关键
    • 抽象
    • 模块化
    • 封装
    • 信息隐藏
    • 关注点分离
数据抽象

有一组操作所刻画的类型,类型的特征是可以对其执行的操作

分类类型和操作
  • 可变(mutable)和不可变(immutable)类型
    可变类型的对象可以更改,提供了可改变内部数据值的操作。
    不可变数据类型其操作不改变数据内部的值,而是构造一个新对象。
  • 抽象类型的操作进行分类
    • 构造器(creators)
      创建该类型的新对象
    • 生产器(producers)
      从类型的旧对象创建一个新对象,比如字符串的拼接
    • 观察器(observers)
      或缺抽象类型的对象并返回不同类型的对象
    • 变值器(mutators)
      改变对象属性的方法
设计一个抽象类型
  • 设计简洁,一致的操作
  • 足以支持客户端对数据所做的所有操作需要,且用操作满足客户端需要的难度要低
  • 要么抽象,要么具体,不要混合
表示独立性(representation independence)RI

客户端使用ADT时无需考虑其内部如何实现,ADT内部表示的变化不应影响外部spec和客户端

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

在任何时候总是true,immutable类型就是不变量,由ADT来负责,与客户端任何行为无关。

  • 作用:保持程序的正确性,不变量是永远不会改变的,因此在所有用到的地方都要检查不变量是否改变
    • private 类内部使用
    • public 类外部可以使用
    • final 强调不可变类型不会再改变了
  • 如何做到不变
    防御式拷贝,意思就是,对于一些本来就可变的数据,比如说像list,date这些,本来就可以改变,如果构造器只是简单的this.time=time;类似这种,他是和传入的对象一直相关,也就是说外部的time改变,里面的就会改变,因此可以this.time=new …
RI和AF
  • R 表示值的空间,ADT关注的
  • A 抽象值的空间:客户端看到和使用的值,客户端关注的
    AF:R->A 满射,未必单射,未必双射,R中的部分值并非合法的,在A中无映射值。
    RI:定义AF的表示值(rep值)的子集,描述了什么是合法的表示值
    综合来说,选择某种特定的表示方式R,进而指定某个子集是合法的(RI),并且为该子集的每个值做出解释(AF)—即如何映射到抽象空间的值
  • 客户端知道的
    abstract value space
    creators
    observers
  • 开发者知道的
    abstract value space
    AF
    creators
    observers
    Rep
    RI
beneficent mutation (有益突变)

只要映射到空间A的值不变,我们就可以改变R空间的取值,但是客户端看不到改变
作用

  • 性能改进
    cache暂存某些频繁计算的结果
    数据结构再平衡
  • 通过牺牲immutability的部分原则来换取效率和性能
记录AF,RI,safety from rep exposure

用注释形式记录

  • RI:
    rep中的所有fields何为有效
  • AF:
    如何解释每一个R值
  • safety from rep exposure:
    给出理由,证明代码并未对外泄露其内部表示
  • spec:
    规约,只能使用客户端可见的内容来撰写,包括参数,返回值,异常等,不应该谈及任何内部表示的细节,以及R空间的任何值
    表示泄露发生,则ADT内部表示可能会在程序的任何位置发生改变
  • ADT是否保持不变量标准
    • 由构造器或者生产器建立
    • 由观察器或者变值器保存
    • 没有表示泄露发生
      比如说返回一个数组,就会发生表示泄露
ADT不变量替换前置条件

用ADT不变量取代复杂的precondition,相当于将复杂的precondition封装到了ADT内部。

这样易于更改,易于理解,且避免出错

summary
  • 抽象数据类型以其操作为特征。

  • 操作可分为创造者、生产者、观察者和变异者。

  • ADT的规范是其操作集及其规范。一个好的ADT是简单的、连贯的、充分的和独立于表现的。

  • ADT通过为其每个操作生成测试进行测试,但在相同的测试中同时使用创建者、生产者、变异者和观察者。

  • safe from bugs。一个好的ADT为一个数据类型提供了一个定义良好的契约,这样客户就知道从数据类型中期望得到什么,而实现者有定义良好的自由来改变。

  • easy to understand。一个好的ADT将其实现隐藏在一组简单的操作后面,这样使用ADT的程序员只需要了解操作,而不需要了解实现的细节。

  • ready for change。表示独立性允许对抽象数据类型的实现进行更改,而不需要对其客户端进行更改。

  • 不变量是在对象的生存期内,ADT对象实例始终为真的属性。

  • 一个好的ADT保留它自己的不变量。不变量必须由创造者和生产者建立,并由观察者和变异者保存。

  • rep不变量指定表示的合法值,并应在运行时使checkRep()进行检查。

  • 抽象函数将具体表示映射到它所表示的抽象值。

  • 表示泄露威胁着表示独立性和不变量的保存。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值