日常中,人与人打交道存在权利与责任,以及信任的问题,这些问题会让人与人之间的交往变得困难,那么为了解决这些困扰,在人与人打交道时会用合约的方式来明确下双方的权利责任。
DBC
软件设计中为了确保软件模块的权利与责任,以确保程序的正确性,也引入了合约的概念,这就是DBC(Design By Contract)按合约设计。
什么是正确的程序?程序只做它声明中要做的事情,不多做也不少做。
DBC的方式:用文档记载并约定软件模块的权利和责任,以确保程序正确性。用文档记载这样的声明,并进行校验,是按合约设计(DBC)的核心所在。
DBC的流程:
1.前条件:为了调用例程,必须为真的条件
2.后条件:例程保证会做的事情
3.类不变项:类确保从调用者的视角来看,该条件总是为真
*如果调用者满足了例程的所有前条件,例程应该保证在其完成时,所有后条件和不变项将为真。
(java中的DBC工具是iContract,书中的例子代码是以iContract写的)
对在开始之前接受的东西要严格,而允诺返回的东西要尽可能少。记住,如果你的合约表明你将接受任何东西,并允诺返回整个世界,那你就有大量代码要写了!
面向对象的继承和多态是合约发挥作用的领域之一。
实现DBC
1.断言
支持断言式编程的语言可以通过断言部分实现DBC。
为什么是部分实现?因为:
首先,断言不支持继承层次向下遗传
其次,断言不支持“老”值。(什么是“老”值?)
最后,runtime和库的设计不支持合约(什么意思?)
2.语言支持
有些语言内建对DBC的支持(Eiffel和Sather)
C,C++的有些预处理器能处理作为特殊注释嵌入在代码中的DBC。预处理器可以把这些注释展开为断言代码(Nana)
Java可以使用iContract
DBC与早崩溃
谁负责检查前条件,调用者?还是被调用的例程?如果是作为语言的一部分实现的,答案是两者都不是。前条件是在调用者调用例程之后,但在进入例程之前,在幕后测试的。因而如果要对参数进行任何显式的检查,就必须由调用者来完成。因为例程永远也不会看到违反了前条件的参数。
通过早崩溃、在问题现场找到和诊断问题要容易的多。
不变项的其他用法
1.循环不变项
循环不变项是对循环最终目标的描述,有时在复杂的循环上设置正确的边界条件会很成问题。循环常有的“香蕉”问题、“篱笆桩”问题、“差一个”问题。这样在循环每次执行前以及迭代时它都是有效的。
2.语义不变项
语义不变项描述的是一种不可违法的需求。固定的需求或不可违反的法则,和一些需求中细化出的政策是要加以区分的。细化的政策是可以动态的变化的。而需求中的一些基本定义是不变的。那么用语义不变项去清晰、简介的定义出那些政策无论怎么变化都不会改变的基本法则。
动态合约与代理
在“自治代理”的领域中。按照自治的定义,代理有权拒绝它们不想接受的请求。“能够互相磋商合约,以实现某个目标”的组件和代理是解决软件生产率危机的方法。