一.方法规约
程序写出来的目的1.给机器看,2.给人看。一个大型项目中一定有程序员的互相交流,而规约就是为了交流存在的。我们不可能考虑所有的情况,所以我们指定一些假设保证我们的程序正确运行需要的内容。我们需要做一些设计决策。为了交流这些东西,我们要书写规约。
规约是使用者与开发者之间的的契约,隔离了具体的细节,让客户端不了解具体实现也能正确调用方法。
二.为什么要写规约?
1.必要性:Bug来自与双方的误解,不把一些设计决策写下来,双方的理解不同
2.重要性:区分责任,隔离细节,了解spec即可工作。
三.行为等价性
两个方法能否互相替代?是个常见的问题,这时候就要行为等价性来判断。
行为等价性:是针对spec来说的,单纯代码无法判定行为等价性。
四.规约的结构
1.require:前置条件对客户端约束
2.effect: 后置条件对开发者的约束
前置条件满足后置条件必须满足,前置未定义,后置可以做任何事情。
五.JAVA规约
首先明确规约并不只是注释,而函数声明也属于规约
1.静态方法声明属于规约,给编译器的规范。里面包含了返回值与参数类型,函数名。
2.注释属于规约,给人看的。
一个JAVA规约
/***
* @param
* @return
* @throws
*/
public xxx xxxx(xxxxxxx)
@param描述前置条件,@return @throws描述后置条件
书写规约千万不能提及内部表示,局部变量,私有变量。而且注释中的规约没有必要提及代码规约已经提及过的东西,返回值,参数类型。
并且有一些要求也必须在规约中,除非规约提到,否则不能修改参数。
六.可变类型让规约变得复杂
可变类型中,多个变量有引用别名。所以导致我们的程序有很多行为需要考虑。
iterator 迭代器就是一个例子,在迭代的过程中,因为集合类可变。如果将集合类中使用本身的remove删除某个对象,就会导致未定义行为,iterator指向就会不确定。
并且要避免使用可变全局。
但在spec中要求开发者或使用者不修改数据的要求是不靠谱的,这是责任推卸,应该多用不可变类型。
七.规约设计
规约属性汇总:
1.陈述性 说清楚情况吗?
2.确定性:一个输入有多种可能合法输出吗?
3.强度:规约合法输入多还是少
规约的强度:
S1>=S2
要求S1的前置条件更弱。
S1后置条件在前置条件相同的情况下更强。
则S1允许替换S2。
若S1前置强于S2,后置弱于S2,S2>=S1
若S1前置弱于S2,后置弱于S2,或无关,S1与S2不兼容。
规约越强:前置越弱,客户端责任越弱,后置越强:开发者责任越强。
越强的规约实现方法越少。