1、文章链接
Reading 7: Designing Specifications
2、文章内容
此篇文章研究类了似行为的不同规范,并讨论它们之间的权衡。将探索是什么使某些规范比其他规范更好。从以下三个方面来比较:
- 是否具有确定性,即,给出的是确定的postcondition,还是众多可能性中的一种。
- 描述性多强,是说明了所有的步骤,还是只给出结果和输出与输入的关系。
- 强壮性多高,postcondition和precondition的强度。
(1)确定性vs不确定性
确定性:当呈现满足前提条件的状态时,结果完全确定。只有一个返回值和一个最终状态是可能的。没有多个有效输出的有效输入。
确定性差不等于不确定性,不确定性必须引入随机化元素。
(2)声明性vs操作性
操作规范给出了该方法执行的一系列步骤;伪代码描述是可操作的。
声明式规范没有给出中间步骤的细节。
相反,它们只是给出最终结果的属性,以及它与初始状态的关系。
(3)更强vs更弱
为了回答这个问题,我们从逻辑中汲取强弱的概念。谓词 P 是更强比谓词 Q (并且 Q 是较弱比 P)如果匹配 P 的状态集是匹配 Q 的状态的严格子集。将“更强”视为更受约束或更严格,而“更弱”则受更少约束、更松散可能会有所帮助。例如,前提条件是对输入状态的谓词,因此使前提条件更强意味着缩小合法输入的集合。后置条件是对输出状态的谓词,因此更强的后置条件会缩小允许的输出和效果集。规范是实现的谓词,因此更强大的规范会缩小合法实现的集合。请注意,如果 P 和 Q 都不是另一个的子集,那么 P 和 Q 也可能无法比较——既不强也不弱。
规范 S2 强于或等于规范 S1 当且仅当
- S2 的前提条件弱于或等于 S1 的前提条件,
并且- 对于满足 S1 前置条件的状态,S2 的后置条件强于或等于 S1 的后置条件。
如果是这种情况,那么满足 S2 的实现也可以用于满足 S1,并且在程序中用 S2 替换 S1 是安全的。
前提条件较弱,但对于满足的前提条件的输入,后置条件也较弱。
(4)绘图规范
规范定义了所有可能实现空间中的一个区域。给定的实现要么按照规范运行,满足前置条件-隐含-后置条件契约(它在区域内),要么不符合规范(在区域外)。
-
实施者可以自由地在规范内移动,更改他们的代码,而不必担心惹恼客户。这对于实现者能够提高算法的性能、代码的清晰度或在发现错误时改变方法等至关重要。
-
客户不知道他们将获得哪种实施方式。他们必须尊重规范,但也可以自由地改变他们使用实现的方式,而不必担心它会突然中断。
(5)设计好的规范
①规范应该是连贯的
一个连贯的规范对于它的客户来说是一个单一的、完整的单元是有意义的。规范不应该有很多不同的情况。长参数列表、启用或禁用行为的布尔标志以及复杂的逻辑都是麻烦的迹象。
②返回结果应提供信息
③规范应该足够强大
规范应该在一般情况下给客户足够强的保证——它需要满足他们的基本要求。在指定特殊情况时,我们必须格外小心,以确保它们不会破坏原本有用的方法。
④规范也应该足够弱规范太强有时会缺少重要的细节,如果出现问题将可能是许多地方出现错误。
⑤规范应尽可能使用抽象类型
用抽象类型编写我们的规范为客户和实现者提供了更多的自由。在 Java 中,这通常意味着使用接口类型,比如
Map
orReader
,而不是特定的实现类型,比如HashMap
orFileReader
。
(6)关于访问控制
将方法设为公共还是私有的决定实际上是关于类契约的决定。程序的其他部分可以自由访问公共方法。公开一个方法,将它宣传为您的班级愿意提供的服务。如果您将所有方法公开——包括真正仅用于类中本地使用的辅助方法——那么程序的其他部分可能会依赖它们,这将使您更难更改将来上课。您的代码不会为更改做好准备。
公开内部辅助方法也会给你的类提供的可见界面添加混乱。保持内部事物的私有性使您的类的公共接口更小且更连贯(意味着它只做一件事并且做得很好)。你的代码会更容易理解。
当我们开始编写具有持久内部状态的类时,我们将在接下来的几个类中看到使用私有的更有力的理由。保护这种状态将有助于保护程序免受错误的影响。
(7)关于静态方法和实例方法
静态方法不与类的任何特定实例相关联,而实例方法(不带
static
关键字声明)必须在特定对象上调用。实例方法规范的编写方式与静态方法规范的编写方式相同,但它们通常会引用调用它们的实例的属性。
3、心得感悟
与往常一样,我们的目标是设计规范,使我们的软件:
-
远离错误。如果没有规范,即使对我们程序的任何部分进行最微小的更改,也可能是翻倒整个事情的多米诺骨牌。结构良好、连贯的规范可以最大限度地减少误解,并最大限度地提高我们在静态检查、仔细推理、测试和代码审查的帮助下编写正确代码的能力。
-
容易理解。编写良好的声明性规范意味着客户不必阅读或理解代码。你可能从来没有读过的代码,这样做对 Python 程序员来说并不像阅读声明规范那样有用。
-
准备好改变。适当弱的规范为实现者提供了自由,而适当强的规范则为客户提供了自由。我们甚至可以自己更改规范,而不必重新访问它们使用的每个地方,只要我们只是加强它们:削弱前置条件和加强后置条件。