HIT软件构造课堂笔记 第六章 抽象数据类型(ADT)

第六章 抽象数据类型(ADT)Abstract Data Type

知识点较多的一章—每一部分都很重要!!!!

信息隐藏/表示独立性

在这里插入图片描述

数据抽象

有一组操作所刻画的数据类型(传统的类型定义:关注数据的具体表示)

抽象类型:focus on operations ,强调“作用于数据上的操作”,程序员和 client无需关心数据如何具体存储的,只需设计/使用操作即可。

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

Classifying the operations of an abstract type

构造器:A creator may take an object as an argument, but not an object of the type being constructed (输入其它类型的,生成当前类型的)

生产器:The concat() method of String , for example, is a producer: it takes two strings and produces a new one representing their concatenation(当前类型生成当前类型)

观察器(observor):生成一个对象(当前的)用来观察其他类型的对象

变值器:对类内部的属性值进行改变(mutable有,immutable无)

在这里插入图片描述

构造器和生产器的区分小,比如没有输入参数时—构造器;有输入时,生产器
在这里插入图片描述

生产器(creator)
  • A creator is either implemented as a constructor , like new ArrayList(), or simply a static method instead, like Arrays.asList(), List.of(). 构造器:可能实现为构造函数或静态函数
  • A creator implemented as a static method is often called a factory method (静态)工厂方法 :把所有可能暴露接口具体实现的静态方法聚集在一起组成一个新的类(后续会再讲)
  • The various String.valueOf(Object Obj) methods in Java are other examples of creators implemented as factory methods. 与 *Object.toString()*正好是相对的
变值器(mutator)
  • 区分mutable和immutable的就是它们是否拥有变值器

  • 变值器通常返回void----所以如果一个方法的返回值为void,那么必然意味着它改变了对象的某些内部状态

  • 变值器也可能返回非空类型,比如Set.add()返回Boolean类型的来确定set是否真正被改变了;In Java’s graphical user interface toolkit, Component.add() returns the object itself, so that multiple add() calls can be chained together.

  • immutable的也可以有变值器

ADT本质也是一个类,使用时不能知道类的属性(比如它用什么数据结构存储数据),只能知道如何使用它:程序员修改内部存储方式的时候不会影响用户的使用。

四种“器”

例子2:四种“类”

设计抽象类型(Designing an Abstract Type)

原则

  1. Rules of thumb 1 设计简洁、一致的操作:程序简洁,用户理解相比于较为复杂的程序是不变的”一致“
  2. Rules of thumb 2 要足以支持client对数据所做的所有操作需要,且 用操作满足client需要的难度要低:比如List提供size()操作,虽然不提供也可以用遍历方式来获取size,但是由于size高频使用,所以如果为用户提供的话会很方便。
表示独立性Representation Independence

ADT就是满足表示独立性的类

满足独立性的类:1、immutable 2、mutable(需要解决它再返回—消除变值器)

即使是含有mutable类型的数据,只要被客户调用后返回的类型都是immutable类型的,就称这个class是满足独立性的类(ADT)–immutable

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

Java中所有的类都是满足表示独立性的----关键词public

For example, the operations offered by List are independent of whether the list is represented as a linked list or as an array.

类似下图的规约才是客户可见的:只看得见操作,看不见属性

客户可见的程序部分

内部表示(例子):private char[] a;

返回时不能直接返回mutable类型的引用,否则外部可以更改内部类型存储的值,这是不安全的。下图为不安全的例子:
在这里插入图片描述

对于immutable类型的对象,我们可以对它直接返回给用户(因为它会创建一个新的指向)(比如把上文的a改成String类型,那明明就是安全的)

考试类型:修复漏洞:1、private 2、return

50%考试概率

另一种更好的书写方式:

另一种更好的书写方式

另一种更好的书写方式2

如上图,此时的start、end只能”看“真正的数据,却不能更改。

另一种方法的详细示意图

用户不能直接访问属性:否则后续难以更改数据类型-----所以属性不要设置成客户可访问(public)

解决表示独立性方法
  1. 返回一个新的数据(值是相同的)(duplicate-copy):繁琐
  2. 利用类似unmodifiable(这部分内容在Data type and Type writing)将mutable转化为immmutable后再返回
  3. 在规约中要求客户:除非迫不得已,否则不要把希望寄托于客户端上,ADT有责任保证自 己的invariants,并避免“表示泄露”。
  4. 最好的办法就是使 用immutable的类型,彻底避免表示泄露
测试抽象类型(Testing an Abstract Data Type)

黑盒测试:

  1. 测试creators, producers, and mutators:调用observers来观察这些 operations的结果是否满足spec; 这三类是不能直接测试的
  2. 测试observers:调用creators, producers, and mutators等方法产生或 改变对象,来看结果是否正确。
  3. 风险:如果被依赖的其他方法有错误,可能导致被测试方法的测试结 果失效

Partition the input spaces of ADT operations

substring :根据对String的理解也可以把它当成creator

想要测试substring,需要利用length,charAt调用它

immutable类型的类不会产生变值器!所以会产生新的对象

不变量 Invariant

不变量ADT:在任何时候总是true(属性的限制)

– Immutability is one crucial invariant: once created, an immutable object should always represent the same value, for its entire lifetime. 例如:immutability就是一个典型的“不变量”

–例如:对于一个数组,其start≤end需要永远成立—“不变量”;再比如影响独立性的public和return mutable(private/final)

–Saying that the ADT preserves its own invariants means that the ADT is responsible for ensuring that its own invariants hold. 由ADT 来负责其不变量,与client端的任何行为无关,其正确性也不依赖于其它的modules

小结

保持不变性和保持表示独立性,是ADT 最重要的一个Invariant!

Rep Invariant and Abstraction Function

程序员看见的空间(数据定义下的):R(representation)+映射(rep)

抽象空间用户可见的:A(abstract space)

程序员、用户可见的空间

映射关系:满射、未必是单射、未必双射

(不符合情况的可能不发生R->A的映射)R中的部分值并非合法的, 在A中无映射值

  • 表示不变性RI:某个具体的“表示”是否是“合法的”
  • 也可将RI看作:所有表示值的一个子集,包含了所有合法的表示值
  • 也可将RI看作:一个条件,描述了什么是“合法”的表示值

可能的考试题:给定“规约”,判断AF是否满足满射、单射、双射

image-20220509094548312

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

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

考试:选择+问答(简答+问答)白盒测试最多出现在选择题里

尽量避免”非单射“

image-20220511102043011

creator,observers:只能看到声明

image-20220511102138307

在这里插入图片描述

Problem 3 必考 :添加的方法不能违背RI的原则

add():不能支持排序功能----如果拥有前三个方法的话,那么绝对不能设计add()来支持这三个方法

image-20220511102917753

所以需要把RI写在规约里,否则别的方法设计时可能会出错

随时检查RI是否满足Checking the Rep Invariant

image-20220511103615525

checkRep:帮助完成在哪出错就在哪报错的功能,如下图

image-20220511103844071

observer:一般只是看而非改变

image-20220511103745294

满射+单射+非双射

设计ADT:

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

而且要把这种选择和解释明确写到代码当中—给程序员写的注释

表示暴露也应该写在规约里

有益的改变(Beneficent mutation)–必考
定义:immutable类型允许改变值
  • With our new understanding of the abstract space A and rep space R, we can refine this definition: the abstract value should never change. 对immutable的ADT来说,它在A空间的abstract value应是不变的

  • But the implementation is free to mutate a rep value as long as it continues to map to the same abstract value, so that the change is invisible to the client. 但其内部表示的R空间中的取值则可以是变化的。

  • 属性值不相等,但是从用户的角度看是相等的:那么这两个属性值不相等的对象就是相等的—对于这种不相等,就是一种允许的变化

  • 故immutable允许包含改变属性值的方法,但是这些需要对用户端而言是不变的(R变A不变)

  • 这种mutation只是改变了R值,并未改变A值,对client来说是 immutable的 ->“AF并非单射”,从一个R值变成了另一个R值 ; 但这并不代表在immutable的类中就可以随意出现mutator!

AF和RI的设计影响到方法设计的具体实现

写AF和RI和泄露安全声明(Documenting AF , RI and rep exposure safety argument)必考
  • 在代码中用注释形式记录AF和RI:如何解释每一个R值---->对应的A值是什么,Rep"数学运算”;rep中的所有fields何为有效---->fields之间的关系,条件限定,精确;
  • 表示泄漏的安全声明:给出理由,证明代码并未对外泄露其内部表示——自证清白

image-20220511110429938

image-20220511111004460

橙色修改建议

image-20220511111018995

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

  • 如果规约里需要提及“值”,只能使用A空间中的“值”。ADT的规约里也不应谈及任何内部表示 的细节,以及R空间中的任何值。

  • ADT的内部表示(私有属性)对外部都应严格不可见

  • 故在代码中以注释的形式写出AF和RI而不 能在Javadoc文档中,防止被外部看到而破坏表示独立性/信息隐藏

如何保持不变量
  • 在对象的初始状态不变量为true,在对象发生变化时,不变量也要 为true
  • 构造器和生产器在创建对象时要确保不变量为true
  • 变值器和观察器(observers可加可不加)在执行时必须保持不变性。
  • 在每个方法return之前,用checkRep()检查不变量是否得以保持。
  • 表示泄漏的风险:一旦泄露,ADT内部表示可能会在程序的任何位置 发生改变(而不是限制在ADT内部),从而无法确保ADT的不变量是 否能够始终保持为true。
  • 用三个标准来检查你的ADT是否保持不变量(ADT设计得好不好)-考试题(较难)
  1. established by creators and producers;
  2. preserved by mutators, and observers; (如果是检测immutable,那么注意要检查mutators)
  3. no representation exposure occurs,

image-20220511112212174

ADT不变量代替Precondition

方法:

  1. image-20220511112333483
  2. 创建新的类来进行测试输入是否符合要求image-20220511112715565
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值