抽象数据类型ADT(1)

  1. 抽象数据类型与表示独立性:能够分离程序中数据结构的形式和对其使用的方式。如何设计良好的抽象数据结构,通过封装来避免客户端获取数据的内部表示(表示泄露),避免潜在的bug–在client和implement之间建立“防火墙”.
  2. ADT的特性:不变量、表示泄露、抽象函数AF、表示不变量RI。
  3. 给出了一个类通过抽象函数和表示不变量来实现ADT意味着什么的更正式的数学概念。
  4. 抽象函数将为我们提供一种在抽象数据类型上清晰定义等式的方法。
  5. 基于数学的形式对ADT的核心特征进行描述并应用于设计中。

抽象和用户定义类型

除了编程语言所提供的基本数据类型和对象数据数据类型,程序员可以定义自己的数据类型。

1. 数据抽象

定义:由一组操作所刻画的数据类型。
-number是可以进行加和乘等操作的东西
-string是可以进行连接或者取子字符串的东西
传统上,程序员会提前定义自己的数据类型,比如创建一种记录日期的类型,具有年月日的整数段。传统的类型定义会更关注数据的具体表示
抽象类型关注于操作,强调“作用于数据上的操作”,程序员和用户无需关心数据如何存储。
注:抽象数据类型是由其操作定义的,与其内部实现无关。
类型T的操作和规约刻画了T的特性。当我们谈论列表类型时,我们的意思并不是链接列表、数组或者任何其他的数据结构代表一个列表,而是指的一组不透明的值,可能的对象可以有列表类型-满足所有操作的规格get(), size()等。

2. 分类类型和操作

  1. 可变和不可变数据类型:无论内置的还是用户定义的类型,都可以分类为可变的或不可变的。
    (1) 可变类型的对象:提供了可改变其内部数据的值的操作
    (2) 不可变数据类型:其操作不可改变内部值,而是构造新的对象
    有时一个类型将以两种形式提供,一种可变,一种不可变,比如:StringBuilder是可变版本的String(两者不是相同的Java类型,也不可互换)
  2. 对抽象类型的操作进行分类:
    (1) 构造器(从无到有):创建该类型的新对象。
    构造器可以将对象作为参数,但是不能作为一个构建中的该类型的对象
    (2) 生产器(从有到新):从该类型的旧对象创建新对象。比如String的conact方法就是一个生产器,它利用两个字符串生成一个表示其串联的新字符串。
    (3) 观察器:获取抽象类型的对象并返回不同的类型。比如List的size()方法就返回一个int型。
    (4) 变值器:改变对象属性的方法。比如List的add()方法,通过在尾部添加元素改变列表的属性。
    构造器:t*->T
    生产器:T+,t*->T
    观察器:T+,t*->T
    变值器:T+,t*->void | t | T
    其中每个T本身就是抽象数据类型,t为其他类型,+标记表示该类型可能在签名的该部分出现一次或多次,*标记表示它出现零次或多次,| 表示或。
  3. 操作的签名:
    构造器可能实现为构造函数或静态函数,实现为静态方法的构造器通常称为工厂方法。
    变值器通常返回void,如果返回值为void,则必然意味着它改变了对象的某些内部状态。变值器也可能返回非空类型

3. 抽象数据类型实例

  1. int:不可变,所以没有变值器
    –构造器:数字文字0,1,2,…
    –生产器:算术运算符+、-、*、/
    –观察器:比较运算符==,!= , < , >
    –变值器:无(它是不可变的)
  2. String:String是Java的字符串类型,字符串是不可变的。
    –构造器:String类的构造函数
    –生产器:concat,substring,toUpperCase
    –观察器:length,chartAt
    -变值器:无
  3. List:List是Java的列表类型,是可变的。
    列表也是一个接口,这意味着其他类提供数据类型的实际实现,如ArrayList和LinkedList。
    –构造器:ArrayList和LinkedList构造函数,Collections.singletonList
    –生产器:Collections.unmodifiableList
    –观察器:size,get
    –变值器:add , remove , addAll , Collections.sort
    在这里插入图片描述

4. 设计抽象数据类型

良好ADT的设计:靠“经验法则”,提供一组操作,设计其行为规约 spec

  1. 经验法则1:设计简洁、一致的操作
    –最好有一些简单的操作,可以以强大的方式进行组合,而不是大量复杂的操作,通过简单操作组和实现复杂的操作,操作的行为应该是内聚的
    –每个操作都应该有一个明确的目的,并且应该有一个连贯的行为,而不是一系列的特殊情况。
    –例如,我们可能不应该向列表中添加求和操作。它可能对使用整数列表的客户有所帮助,但是字符串列表呢?还是嵌套列表?所有这些特殊情况会使sum操作变得难以理解和使用。
  2. 经验法则2:要足以支持用户对数据所做的所有操作需要,且用操作满足用户需要的难度要低
    操作集应该是足够的,因为必须有足够的操作来完成用户可能想要完成的计算。
    –一个好的测试是检查该类型的对象的每个属性都可以被提取。判断方法:对象每个需要被访问到的属性是否都能够被访问到
    例如,如果没有get操作,我们将无法找到列表的元素。没有get()操作就无法获取目录的内部数据
    –基本信息应该不难获得。
    例如,size方法对于List来说并不是严格必要的,因为我们可以在递增索引上应用get,直到失败,但这是低效和不方便的。用遍历方式获取List的size太复杂了,但是提供size()操作,会方便用户使用

5. 表示独立性

一个好的抽象数据类型应该是表示独立的。
表示独立性:客户端使用ADT时无需考虑其内部如何实
现,ADT内部表示的变化不应影响外部spec和客户端。
–抽象类型的使用独立于其表示(用于实现它的实际数据结构或数据字段),因此表示的变化对抽象类型本身之外的代码没有影响。
–例如,“List”提供的操作与列表是以链表还是数组表示无关。
您将根本无法更改ADT的表示,除非其操作完全由前提条件和后置条件指定,以便客户知道依赖什么,并且您知道您可以安全地更改什么。通过前提条件和后置条件充分刻画了ADT的操作,spec规定了client和implementer之间的契约,明确了client知道可以依赖哪些内容,implementer(执行者)知道可以安全更改的内容。

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值