3.2 Specification 方法的规约Spec
规约示例
![](https://i-blog.csdnimg.cn/blog_migrate/f32ecb465a02d36ca919bad9156c084a.png)
静态类型声明是一种规约,可据此进行静态类型检查static checking;
方法前的注释也是一种规约,但需人工判定其是否满足
规约作用
规约可以隔离“变化”,无需通知客户端;
规约也可以提高代码效率;
规约:扮演“防火墙”角色;
行为等价性
根据规约判断是否行为等价。不同函数符合同一规约,则它们等价。
例:
![](https://i-blog.csdnimg.cn/blog_migrate/6dec8a0da9ef322cf4603afce84a80ed.jpeg)
行为不同,但满足同一spec,等价
![](https://i-blog.csdnimg.cn/blog_migrate/d8a2d16c2ee889b7abefcebcfc4a86e2.jpeg)
requires / effects 前置条件和后置条件
requires ——precondition 前置条件:对客户端的约束,在使用方法时必须满足的条件
effects——post-condition 后置条件:对开发者的约束,方法结束时必须满足的条件
规定:(1)前置条件满足,则后置条件必须满足;
(2)前置条件不满足,则方法可做任何事情
![](https://i-blog.csdnimg.cn/blog_migrate/06e1d2dfcf2553e4cea72fc0d1955e98.jpeg)
Mutate
除非在后置条件里声明过,否则方法内部不应该改变输入参数;
避免使用可变的全局;
规约分类
- 确定的规约:给定一个满足precondition的输入,其输出是唯一的
![](https://i-blog.csdnimg.cn/blog_migrate/5d3bc1bf17be4694be1c7ab6c4fcc439.png)
- 欠定的规约:同一个输入可以有多个输出
![](https://i-blog.csdnimg.cn/blog_migrate/f714bd29641ec7c3c6fb89dbf0c46f45.jpeg)
欠定的规约通常有确定的实现
- 非确定的规约:同一个输入,多次执行时得到的输出可能不同
- 操作式规约,例如:伪代码;
- 声明式规约:没有内部实现的描述,只有“初-终”状态。更有价值。
![](https://i-blog.csdnimg.cn/blog_migrate/af7eb24cdf88ab9abd2abbf013b043be.jpeg)
规约的强度
spec变强:更放松的前置条件+更严格的后置
![](https://i-blog.csdnimg.cn/blog_migrate/8af64502385967cf7a840e9285a60321.jpeg)
![](https://i-blog.csdnimg.cn/blog_migrate/18b2685939a153f3f5427daf58812611.jpeg)
如何写一个Spec
- Spec描述的功能应单一、简单、易理解
- 信息丰富,不能让客户端产生理解的歧义
- 强度适中
太弱:
![](https://i-blog.csdnimg.cn/blog_migrate/3ceb72e66ac62ab5bae5d2710e8724e3.jpeg)
太强:
![](https://i-blog.csdnimg.cn/blog_migrate/548c3b8cb2604bc5f2590378a527a582.jpeg)
![](https://i-blog.csdnimg.cn/blog_migrate/8f400b00b76d3f61fddaf65ce5842093.jpeg)
4.在规约里使用抽象类型,可以给方法的实现体与客户端更大的自由度
![](https://i-blog.csdnimg.cn/blog_migrate/a858f5adb47f270626bb84144ce5c6f7.jpeg)
5.前置条件:客户端不喜欢太强的precondition,不满足precondition的输入会导致失败。
惯用做法是:不限定太强的precondition,而是在post-condition中抛出异常:输入不合法;尽可能在错误的根源处fail,避免其大规模扩散。
![](https://i-blog.csdnimg.cn/blog_migrate/5fdf4d6315e338d03dbd264564c72320.jpeg)