设计规约(Designing Specification)
概念定义
写在方法前面的说明性注释,用来解释方法的功能、参数、返回值等。如下图所示
规约的好处
- 记录自己的设计决策,供自已或他人阅读。
- 团队协作中,如果没有规约就无法分派任务,无法写程序;即使写出来,也无法验证对错。
- 规约作为一种客户端与程序之间的“契约”,可以明确双方的责任。
- 规约可以隔离变化,无需通知客户端,即不管具体实现如何修改,只要符合规约,客户端就没必要知道修改的具体内容。
- 达到解耦的目标。
- 可以利用规约来判定方法的行为等价性。
- 测试用例可以根据规约来编写。
规约的组成
规约由对方法的解释、前置条件、后置条件组成,不同的语言的规约形式有不同的写法。下图为Java的规约格式。规约会被记录在java doc文档中。
规约的分类
按照强弱分类
规约A强度>B规约强度意味着下面两点:
- A的前置条件更弱
- A的后置条件更强
前置条件和后置条件的强弱由条件的严格程度决定,即如果条件越放松,那么这个条件越弱。反之亦然。
如果要增强一个规约的强度,那么就意味着更松的前置条件+更严格的后置条件。
上图中第二个规约的前置条件比第一个规约的前置条件更加放松,因此规约变强。第三个规约的后置条件更加严格,所以强度更高。
但是要注意一点,后置条件的范围变大,并不意味着后置条件就变弱了,是否变弱需要看前置条件对应的那一部分后置条件是否变弱。如下图,规约二的前置条件变弱了,后置条件的范围变大,但是在满足规约一中的前置条件的情况下,此后置条件并没有变化,所以后置条件并没有变弱。因此整个规约二的强度变大了。
再看下面这个例子,在满足规约一的前置条件的情况下,规约二的后置条件相对于规约一的后置条件变弱了。但是由于前置条件也是变弱,因此无法比较这两个规约的强弱。
按照确定性分类
确定性规约(Deterministic):给定前置条件,其输出是唯一的、明确的。
欠定的规约(Underdetermined):同一个输入可以有多个输出,但是一旦使用具体的方法实现了这个规约,那么这个返回值也将会被确定。
非确定的规约(Not deterministic):同一个输入,多次执行可能得到多个结果,比如涉及到随机数的方法。
按照陈述性分类
操作式规约:有具体的实现细节,如伪代码
声明式规约:没有内部实现的描述,只有对输入输出的规定
声明式规约更有价值,更能应对变化。但是操作式规约能够方便开发。
如何设计好的规约
设计规约的一些原则
- 除非在后置条件中声明过,否则方法内部不应该修改输入的参数。
- 尽量避免使用可变的对象,程序中很多变量指向同一个可变变量,会导致很多问题。
- 方法中尽量对输入的参数进行检查,检查是否满足规约,但是如果代价太大,可以不这样做。
- 规约描述的功能尽量单一、简单、易理解。
- 应该尽可能考虑各种特殊情况,并在后置条件中给出处理措施。
- 在规约里使用抽象类型,可以给方法的实现体与客户端更大的自由度。
- 不要限定太强的前置条件,而是在后置条件中抛出异常:输入不合法。
理措施。
- 在规约里使用抽象类型,可以给方法的实现体与客户端更大的自由度。
- 不要限定太强的前置条件,而是在后置条件中抛出异常:输入不合法。