在编写程序的时候我们往往会面向编译器进行对话,编写逻辑正确、语法正确的程序以便通过静态检查,让编译器信服。但是只与编译器进行沟通是远远不够的,我们编写出的代码要符合现实情况而且要让其他程序员以及未来的自己读懂,所以我们需要编写文档(Documentation)来说明我们的程序,这种文档常常书写在源代码中,以注释的形式存在。
其中对于方法来说,一个重要的文档便是规约(Specification)
规约(Specification)
规约(Specification)就是一个包含着方法描述、开发者和用户需遵守的规则、参数和返回值信息、可能抛出的异常等的文档,规约可以消除用户和其他开发者对作者的误解、区分供需双方的责任,同时也便于定位错误。用户往往不需要直接阅读代码,只需要阅读spec即可理解代码的含义和使用方法。
规约隐藏了代码的具体实现过程,告诉用户,只要你的输入符合我对你的要求,那么就一定能得到我所说的答案。同时规约将实现和调用区分开来,每次修改代码时不用通知用户,只要修改规约即可。规约充当着用户和开发者之间的缓冲。
行为等价性(Behavioral equivalence)
拥有规约后我们就可以通过规约来判断两种方法是否行为等价了,所谓行为等价,意思就是站在用户的角度、站在规约的角度看两种方法是否等价,例如:
前置条件和后置条件
前置条件就是规约中对用户的要求,要求输入的参数满足某种特性;后置条件就是规约中对开发者的要求,要求输出的返回值满足某种特性。当前置条件满足的时候后置条件必须被满足(开发者的义务);但是当前置条件不满足的时候,后置条件是否满足是不可预测的(你违约在先,我自然不遵守义务)。
另外,如果没有特别说明,开发者是不允许直接修改输入的参数的(如果参数是可变的),为了保证安全性,我们要尽量使用不可变的类型作为参数输入、作为返回值输出,并且避免可变的全局变量。众所周知,良心是靠不住的。
我们说一个规约变强了,指的是前置条件更弱、后置条件更小。如果一个规约变强了,那也就导致了用户的义务减少了,开发者的义务增加了,同时开发者的自由度也降低了。编程时我们不能使用太强的规约——虽然用户更开心,但是往往极强的规约无法达到,开发者会面临着巨大的实现难度;也不能使用太弱的规约——方法要满足用户的需求,且不能抛出过多的异常让用户迷惑(异常之后的结果是什么?参数是否改变了?),我们需要对不满足前置条件所抛出的异常进行足够的说明。
总结
综上所述,规约的编写是软件构造中的重要步骤,我们可以灵活的编写规约,设定用户和自身的责任,对于自身可实现的内容就尽可能的加强规约,对于某些特殊的输入造成的难以判断的错误则交给用户去避免。