Specification、前置/后置条件
规约示例:
/**
* Compute a hailstone sequence.
* @param n Starting number for sequence. Assumes n > 0.参数
* @return hailstone sequence starting with n and ending with 1.返回值
*/
public static List<Integer> hailstoneSequence(int n) {
构成:
前置条件:对客户端的约束,在使用方法时必须满足的条件Precondition requires
后置条件:对开发者的约束,方法结束时必须满足的条件 Postcondition effects
异常行为:如果违反了前提条件,它会做什么(抛出异常)
方法签名
前置条件满足,则后置条件必须满足。前置条件不满足,则方法可做任何事情。
当前置条件被违反时,说明客户端有bug,尽管实现者没有义务提醒,但可通过快速失败使bug更容易被找到和修复。
当前置条件被违反时,说明客户端有bug,尽管实现者没有义务提醒,但可通过快速失败使bug更容易被找到和修复。
不要提具体实现、局部变量
除非在后置条件里声明过,否则方法内部不应该改变输入参数
行为等价性
是否可相互替换
站在客户端视角看行为等价性
单纯的看实现代码,并不足以判定不同的implmentation方法是否是“行为等价的”
需要根据代码的spec规约(开发者与client用户之间形成的contract约定)判定
行为等价性在编写代码之前,需要弄清楚spec如何协商形成、如何撰写
规约的强度
S2前置条件更弱或相等(不强于)S1且S2后置条件更强或相等(不弱于)S1(比较后置条件建立在S1的前提条件上),规约的强度S2>=S1, 就可以用S2替代S1
spec变强:更放松的前置条件+更严格的后置条件
规约越强,更少的实现,更多的clients用户端可以调用
某个具体方法(用点表示)实现,若满足规约,则落在其范围内;否则,在其之外。
更强的规约,表达为更小的区域
更强的后置 条件意味着实现的自由度更低了 ➔在图中的面积更小
更弱的前置条件意味着 实现时要处理更多的可能输入, 实现的自由度低了➔面积更小
好的规约应功能单一、无歧义、尽可能考虑各种特殊情况,在post-condition给出处理措施、不限定太强的precondition,而是在postcondition中抛出异常:输入不合法。最好快速失败,尽可能靠近bug的站点,而不是让错误值通过远离其原始原因的程序传播