目录
1.什么是规约
2.行为等价性
3.确定的规约vs非确定的规约
3.1确定的规约
3.2非确定的规约
4.声明式规约vs操作式规约
4.1声明式规约
4.2操作式规约
5.规约的组成
5.1前置条件
5.2后置条件
5.3例子
6.规约应该展示的内容
7.设计规约
7.1规约的强弱
7.2图画规约
7.3设计一个好的规约
7.4一般的约定
1.什么是规约
规约包括方法的注释和方法名和参数等,不包括方法的实现体(方法块内的注释不算)。
规约就是注释,不能被编译器检测(×)
方法部分还是能被编译器静态检测出来的。
规约只讲“能做什么”,不讲“怎么实现”。
2.行为等价性
站在用户的角度看方法是否等价,而不是从实现的方式,只要同时能满足用户的需求,则等价。
3.确定的规约vs非确定的规约
3.1确定的规约
对于同一输入,返回的是确定的值。
3.2非确定的规约
对于同一输入,返回的不是确定的值。
4.声明式规约vs操作式规约
4.1声明式规约
声明性规约没有给出中间步骤的细节。相反,它们只是给出最终结果的属性,以及它与初始状态的关系。
4.2操作式规约
操作式规约(用伪代码或者笔述)给出了方法的实现大致思路,例如告诉客户这个数组是从左往右遍历的。
5.规约的组成
5.1前置条件
对客户端的约束,在使用方法时必须满足的条件。包括方法声明满足的参数条件和require中的条件。例如,方法声明中的参数输入必须是整数和数组,require要求改整数必须大于等于0,该整数必须在数组中出现且仅出现一次。
5.2后置条件
对开发端的约束,在方法结束时必须满足的条件。包括返回值的类型必须要正确和effect中的条件。例如,返回值必须是整数,effect中要求出错时要抛出异常。
5.3例子
如果会对输入的参数进行改变的,那么一定要写入规约中,一般除非后置条件里声明,否则不应该改变输入的参数:
6.规约应该展示的内容
一个规约可以涉及方法的输入参数和返回值,但是不能涉及方法的局部变量或者类的私有属性或者实现细节。
7.设计规约
7.1规约的强弱
有两个规约S1、S2,如果S1的前置条件更弱且后置条件更强,则说明S1的规约比S2的规约要强(条件越弱说明越容易满足)。如下例:
以下情况不可比较:
一个规约很强意味着什么:
①更少的实现能满足它(因为规约变强了,那么实现它也越难)
②更多的客户可以使用它
7.2图画规约
下图中每一个点代表一个方法的实现,每一个椭圆代表一种规约限定的范围(圆越小,规约越强),即点若处在椭圆内,则该方法满足这个规约。
更强的规约需要(相对而言)更小的面积的椭圆来表示,具有更强规约的方法除以更内层因为它可以满足的规约更多。
7.3设计一个好的规约
(1)内聚性
即设计的规约功能单一,简单,易理解。下面是反例,有两个功能,应拆分成两个方法来实现。
(2) 强壮性
即需要告知用户这个方法在一般和特殊情况时会怎么处理,参数会怎么变化,返回值会怎么变化。以下这个例子只是说明了遇到null会抛出异常,但没有说明list1和list2会如何变化。
(3)规约可以适当弱一些
(4)使用抽象数据类型
使用抽象数据类型而不是具体的数据类型。
(5)是否使用前置条件
如果使用,则方便了程序员,限制了用户;如果不使用,则为难了程序员,方便了用户。需要根据代价掂量。例如,假如一个方法需要的前置条件是输入参数是一个递增的数组,如果不写该前置条件,则在方法里进行check的代价太大了,还是写的好。
(6)明确性
方法调用的返回应该是一个明确的结果。如下例:
这个规约设计不好,原因是当返回值为NULL时,无法确定是因为存在一个键值对应NULL还是不存在而返回NULL。
7.4一般的约定
① 除非规约中有明确声明在输入参数和返回参数允许使用NULL,一般的方法和类的设计是不允许出现NULL作为输入和返回的(如果设计方法和类时允许出现NULL,则必须在规约中显式地声明)。
②除非规约中有明确声明在输入参数和返回参数补允许使用空串,一般的方法和类的设计是允许出现空串作为输入和返回的(如果设计方法和类时不允许出现空串,则必须在规约中显式地声明)。
③如果规约中不明确地声明可能会出现异常,一般是默认不会出现异常。倘若设计方法或者类时会出现异常,那么就需要在规约中以@throws的形式写出来。
声明:本站部分文章及图片源自用户投稿,如本站任何资料有侵权请您尽早请联系jinwei@zod.com.cn进行处理,非常感谢!