2022 哈尔滨工业大学 软件构造 期末复习笔记3 ADT相关

第5章 规约(specification)

1.编程语言中的函数&方法

参数类型:静态检查是否匹配;
返回值类型:也是;
方法:

  • 客户端使用方法而无需知道内部实现,是一种抽象;
  • 包括规约spec和实现体implementation;

2.规约Specification:面向沟通编程

1)编程中的文档

文档假设assumption

  • 定义变量的数据类型
  • 使用final定义设计决策

面向沟通编程

  • 为什么写“假设”——防止自己记不住&别人看不懂;

  • 两个目标:

    • 代码体现的设计决策,让编译器看懂;
    • 注释写明设计决策:让人看懂;

2)(方法的)规约

是程序与客户端达成的一致,为双方确定责任,调用时都要遵守;

3)行为等价性

  • 以客户端视角看行为等价性——是否可以互相替换;
  • 根据规约判断是否行为等价——规约相同,等价;

4)规约结构:前置条件和后置条件

规约结构

  • 规约的内容:
    • 前置条件,关键字requires,使用@annotation说明
    • 后置条件,关键字effects,使用@return说明
    • 例外行为:违反规约后的结果
  • 前置条件:对客户端的约束,使用方法时需要满足的条件;
  • 后置条件:对开发者的约束,方法结束后满足的条件;
  • 契约:如果前置条件满足,后置条件必须满足;
  • 而前置条件不满足,方法可以做任何事情;

java的规约

  • 静态类型声明是一种规约;
  • 方法前的注释也是一种规约

3.设计规约

规约的强度(更强):

  • 前置条件更弱;
  • 后置条件更强;

spec变强=更放松的前置条件+更严格的后置条件;

第6章 ADT 抽象数据型

0 抽象数据类型和表示独立性:

设计抽象数据结构,通过封装避免客户端client获取数据类型的内部表示,实现implementer对于用户client不可见,防止bug。

AF:abstraction functions,
RI:representation invariants

1 Abstraction and user-defined types

类型:

  • built-in
  • user-defined

数据抽象:

  • 包括数据、数据上能执行的操作;
  • 传统类型更注重数据本身(比如内置类型),而抽象类型(各种java class)更注重数据上的操作;

抽象数据类型是由它的操作定义的

  • e.g.提到列表,不是指它的实现是链表还是数组,而是说有着列表能够实现的操作:get(),size(),etc;

2 类型和操作的分类可变类型和不可变类型:

  • mutable/可变类型:对象提供了可以改变其内部数据的值的操作;

改变 一般指改变引用,改变值 指改变引用/指向的数据

  • immutable/不变数据类型:操作不能改变内部值,而是构造新的对象(或者什么都不改变)

四类ADT操作:

  • creators 构造器
    • 实现:构造函数constructor(构造实例)或静态方法(不受实例影响)
  • producers 生产器
    • 使用一个旧对象,返回一个新对象;//已有对象“生”出新对象
    • e.g. String.concat();
  • observers 观察器
    • 接受一个对象,返回一个非对象类型;
    • e.g. size()
  • mutators 变值器
    • 能够改变对象属性(内部数据)的方法;
    • e.g. add();

构造器的特点

  • 一个creator或者是构造函数constructor,或者是一个静态函数;
  • 通过静态函数实现的creator通常称为factory method(工厂方法);
  • 比如String.valueof(Object obj)是通过工厂方法构造的String;

除了构造函数本身以外,直接使用值创造对象的都是构造器

mutator的特点

  • 变值器通常返回void;
  • 也可能返回非空类型,比如栈的弹栈&取值

3 例子

Integer,String,List

4 设计一个抽象类型

  • 操作简单一致;
  • 提供的操作足以满足用户需求,同时足够简单;

5 表示独立性 RI Representation Indepdence

  • 用户使用ADT时不需要考虑内部实现,内部实现的变化不影响外部spec(规约)和客户端;
  • 换言之,RI就是说,程序员为客户端提供ADT的各种操作,然后只要坚持操作的规约,不改变其输入和输出(格式),只修改内部实现而不影响客户端使用;

不同的实现为客户端提供相同的功能

ADT的snapshot画法(参考第四章内容)

6 测试

相当于黑盒测试(因为内部数据对于用户不可见)

  • 测试creators、producers、mutators:调用observes观察这些操作的结果是否满足spec;

spec是设计规约,程序和客户端都要遵守的要求

  • 测试observers:调用其他三种方法或者改变对象,看结果是否符合预期;

7 不变量 Invariants

  • ADT的不变量正如其名,不会发生改变,任何时候都是true
  • 比如immutability
  • 由ADT/设计者负责,客户端无关

8 Rep Invariant and Abstract Function

两种 值空间

  • R:表示空间(变量空间?(数据的)代表空间?)
  • A:抽象空间(数值、数据空间?

R、A构成的图,R到A的映射,R指向A

  • R到A为满射
  • 未必单射(所以未必双射)

抽象函数(Abstraction Function,AF):R和A之间映射关系的函数,即如何解释R为A中的一个值(为R中的一个对象分配A中的一个值)
Rep Invariant,PI:

  • 一个PI将R中的值映射到布尔值T/F;

  • 对于一个rep value(R中的值,表示值)r,RI(r)为真当且仅当r被AF映射;

  • 换言之,RI表示了一个给定的rep value是否是规定好的、(可)“合法”(使用)的;

  • RI的值取决于AF,算是AF的一个observer?HH

AF、RI如何决定

  • 抽象值空间本身不能决定AF、RI,不同的内部表示可以在相同的abstract value space上设计不同的AF、RI;

根据RI、AF设计ADT

  • 首先选择R和A;
  • 由RI确定合法的表示值;
  • 由AF解释合法的表示值;
  • 做出对R、A、RI、AF的选择,要写进代码里(注释?)使之后使用者能意识到这些表示的意义;

随时检测RI是否为真

  • 在所有改变rep/表示值的方法内都要检查(改变后是否满足RI);
  • Observer方法(类似const、只读)可以不检查

9.Beneficent mutation 有益的可变性

  • 对于抽象值,A空间里的值应该永远不被改变;
  • 但是表示值可以作为mutable的,只要保持映射向相同的抽象值;
  • 对于immutable的ADT,在A空间中的抽象值应该保持不变;但其内部表示的R空间中的取值可以变;
    • e.g.对于除法运算,被除数和除数同时乘-1,对结果无影响;

10.Documenting the AF、RI,Safety from Rep Exposure 记录AF、RI,暴露表示值的安全性

记录AF、RI

  • 在代码中用注释记录AF、RI;
  • RI:表示值中的field如何才有效;
  • AF:如何解释R值;

ADT spec包含什么:

  • ADT的规约只能用client可见的内容来撰写,包括参数、返回值、异常;
  • 如果规约中需要提到“值”,只能使用A空间里的;

11.ADT不变量替换条件

用不变量取代复杂的precondition,相当于把前提封装到ADT内部;

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值