软件构造——规约和ADT复习总结

本文探讨了编程中的方法、规约和抽象数据类型(ADT)的设计原则。方法是程序的基础,通过前置条件和后置条件确保行为等价性。强调了可变方法的规范,指出应尽量避免可变对象以减少bug。在设计ADT时,应确保表示独立性,维持不变量,并通过测试验证规约。规约的强化有助于提高代码的稳定性和可维护性。
摘要由CSDN通过智能技术生成

Spec

编程语言的方法

“方法”是程序的“积木”,可以被独立开发、测试、复用
使用“方法”的客户端,无需了解方法内部具体如何工作—“抽象”

行为等价性

为了确定行为等价性,问题是我们是否可以用一个实现替代另一个实现(是否可相互替代)
根据规约判断是否行为等价
在这里插入图片描述
规约的结构:

  • 前置条件:对客户端的约束,在使用方法时必须满足的条件
  • 后置条件:对开发者的约束,方法结束时必须满足的条件
  • 特殊行为
    -契约:如果前置条件满足了,后置条件必须满足

作为实现者,如果违反了前提条件,可以选择抛出异常
当违反了我们的前提条件时,客户端就会有一个错误。我们可以通过快速失败来使这个错误更容易被发现和修复,即使我们没有义务这样做。

静态类型声明是一种规约,可据此进行静态类型检查static checking。
方法前的注释也是一种规约,但需人工判定其是否满足。
在这里插入图片描述
在可能的情况下,将前置条件放入@param中,并将后置条件放入@retern和@throws中。

在这里插入图片描述

可变方法的规范

  • 除非在后置条件里声明过,否则方法内部不应该改变输入参数。
  • 应尽量遵循此规则,尽量不设计mutating的spec,否则就容易引发bugs。
  • 尽量避免使用mutable的对象

可变的对象使简单的契约变得复杂
程序中可能有很多变量指向同一个可变对象(别名)
无法强迫类的实现体和客户端不保存可变变量的“别名”。
避免使用可变的全局变量!
可变数据类型导致程序修改变得异常困难!
一个例子:在数据库中查找用户名并返回用户的9位标识符的方法
在这里插入图片描述
现在,客户端和实现者都分别决定做出更改。

  • 客户担心用户的隐私,并决定模糊id的前5位数字:

在这里插入图片描述

  • 实现者担心数据库上的速度和负载,因此实现者引入了一个可以记住已查找过的用户名的缓存:在这里插入图片描述

结果导致:
在这里插入图片描述
将返回值类型定义为String
在这里插入图片描述
关键就在于“不可变”,在规约里限定住。

测试和验证规约

在这里插入图片描述

设计规约

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

在这里插入图片描述
越强的规约,意味着implementor的自由度和责任越重,而client的
责任越轻。

确定的规约

确定的规约:给定一个满足precondition的输入,其输出是唯一的、明确的
非确定的规约:同一个输入,
多次执行时得到的输出可能不同

操作式规约vs申明式规约

操作式规约,例如:伪代码
声明式规约:没有内部实现的描述,只有“初-终”状态

  • 内部实现的细节不在规约里呈现,放在
    代码实现体内部注释里呈现

是否使用前置条件取决于

  • (1) check的代价;
  • (2) 方法的使用范围
    – 如果只在类的内部使用该方法(private),那么可以不使用前置条件,在使用该方法的各个位置进行check——责任交给内部client;
    – 如果在其他地方使用该方法(public),那么必须要使用前置条件,若client端不满足则方法抛出异常

ADT

§ 抽象数据类型与表示独立性:如何设计良好的抽象数据结构,通过封装来避免客户端获取数据的内部表示(即“表示泄露”),避免潜在
的bug——在client和implementer之间建立“防火墙”

设计一个ADT

Rules of thumb 1 设计简洁、一致的操作

  • 少而精的操作
  • 操作目的明确,行为连贯

Rules of thumb 2 要足以支持client对数据所做的所有操作需要,且
用操作满足client需要的难度要低

  • 可以提取该类型对象的每个属性。
  • 基本信息不应太难获得

Rules of thumb 3 要么抽象、要么具体,不要混合 — 要么针对抽象
设计,要么针对具体应用的设计。

表示独立性

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

How to test an ADT

§测试creators, producers, and mutators:调用observers来观察这些operations的结果是否满足spec;
§ 测试observers:调用creators, producers, and mutators等方法产生或改变对象,来看结果是否正确。
§ 风险:如果被依赖的其他方法有错误,可能导致被测试方法的测试结
果失效。
在这里插入图片描述

ADT的规约要写什么

ADT的规约里只能使用client可见的内容来撰写,包括参数、返
回值、异常等。
如果规约里需要提及“值”,只能使用A空间中的“值”。
在这里插入图片描述

如何建立不变量

在对象的初始状态不变量为true,在对象发生变化时,不变量也要为true
构造器和生产器在创建对象时要确保不变量为true
变值器和观察器在执行时必须保持不变性。
在每个方法return之前,用checkRep()检查不变量是否得以保持。
表示泄漏的风险:一旦泄露,ADT内部表示可能会在程序的任何位置发生改变(而不是限制在ADT内部),从而无法确保ADT的不变量是否能够始终保持为true。
检查ADT是否保持不变量的三个标准:

  • 由构造器和生产器确立
  • 由观察器和变值器保存
  • 没有表示泄露

用ADT不变量取代复杂的Precondition,相当于将复杂的precondition封装到了ADT内部。
在这里插入图片描述

优点:
-避免错误更安全,因为所需条件(无重复排序)可以在一个地方、排序集类型执行,而且使用Java静态检查,防止使用完全不满足此条件的值,在编译时出现错误
-它更容易理解,因为它要简单得多,而且 SortedSet名称表达了程序员需要知道的内容
-它更准备好进行更改,因为现在可以更改排序集的表示,而无需更改exclusiveOr或其任何客户端。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值