哈工大软件构造复习之Specification
Specification
作用
- 规约可以隔离"变化",无需通知客户端
- 规约可以提高代码效率
- 规约扮演"防火墙"角色
- 解耦,不需要了解具体实现
内容
只讲"能做什么",而不讲"怎么实现"
Behavior equivalence 行为等价性
是否可以相互替换
- 站在客户端的视角看行为等价性,不同的行为,对用户来说(根据用户需求)可能等价!
- 根据规约判断行为等价,两个方法符合同一个规约,则等价
规约的结构
- Pre-condition
- Post-condition
- Exceptional behavior 异常行为,如果违背了前置条件,会发生什么
规约的强度与替换
Spec变强:更放松的前置条件(前置条件更弱)+更严格的后置条件(后置条件你更强),
两条件同时变强或变弱则无法比较。
若规约强度S2>=S1,则可以用S2替换S1。
deterministic spec & undetermined spec 确定的规约和欠定的规约
- 确定的规约:给定一个满足前置条件的输入,其输出唯一、明确
- 欠定的规约:同一个输入可以有多个输出(多次执行输出可能不同)
Declarative spec & operational spec 声明式规约和操作式规约
操作式规约:如 伪代码
声明式规约:没有内部实现的描述,只有"初-终"状态
声明式规约更有价值!
内部实现的细节不在规约里呈现,而放在代码实现体内部注释里呈现。
Diagraming specification
规约定义一个区域,该区域包含所有可能的实现方式。
空间中的每个点表示一种方法的实现。
对于某个具体实现,若满足规约,则落在其区域内。
更强的规约表达为更小的区域。
Quality of specification 规约质量
- 内聚性:spec描述的功能应单一、简单、易理解
- 运行结果信息丰富(可能的改变,以及返回值等),不能让客户端产生理解上的歧义
- 足够强(如postcondition中充分阐述各种情况)
- 适当弱(太强的规约,在很多特殊情况下难以达到)
- 在规约里使用抽象类型(在java中,经常使用interface,如Map、List,而不是HashMap、ArrayList),可以给方法的实现体和客户端更大的自由度
- 使用前置条件和后置条件?
客户端不喜欢太强的pre-condition,不满足precondition的输入会导致失败
So:不限定太强的precondition,而在postcondition中抛出异常:输入不合法,
fail fast,避免fail大规模扩散
是否使用前置条件取决于:
- check(检查参数合法性)的代价
- 方法的使用范围:
如果只在类内部使用(private),则可以不使用precondition,在使用该方法的各个位置进行check
如果在其他地方使用(public),则必须使用precondition,若client不满足则抛出异常