按照契约式开发方法论来设计可以减少许多编码中的错误。以下是一个与此相关的介绍。
契约式设计是一个软件范例,使用它可以确保你的编码的错误更少。它通过执行“契约”来达到这一步。当你输入参数(前提条件)时,你期望得到什么,当你退出(后置条件)时又会产生什么样的结果,这些功能决定了一份契约的订立。例如,在函数int factorial(int n)中,你希望n是正的(前提条件),也希望它会产生一个正值(后置条件)。许多程序员们相信,如果利用契约式设计范例中的那些设计,他们的编码就会保持较少错误的情况,而且他们的经验也证明了事实确实如此。
如何运行
一个使用了契约式设计(DbyC)的函数存在前提条件和后置条件,当然这些前提条件和后置条件应该是适当的,而且通过测试也证明了它们确实存在。
在C++中,你可以这样使用DbyC:
· 使用assert函数(或者其它一些相类似的宏)
· 当一个前提条件或后置条件失败时,抛出一个异常
· 使用assert函数并抛出一个异常
使用assert函数并抛出一个异常是首选方法。在本文中,我们将要讨论它为何是首选,以及怎样更有效地执行它。
契约式设计的有效性
契约式设计可以帮你在两种情况下(图表A)提前捕获错误:
· 在你的契约式设计函数中,如果对于某些参数来说结果是错误的。
· 在客户端编码中,当你调用了一个契约式函数时,如果你错误地通过了一个不正确的参数的联合。
如果你的函数并不处理所输入的数据时,你就要使用前提条件了,例如,当数据对该函数不发生任何影响的时候(比如,用一个负值去调用一个阶乘函数)。你要用后置条件来测试该函数的输出值是否正确(例如,发个阶乘函数应该返回一个正值)。
如果说一份契约被破坏了(它的前提条件或后置条件失败),就相当宣布了一个设计错误。它意味着一个函数或客户代码中的一者调用该函数时,该函数就包含了一个语义错误。一般情况下,当前提条件或后置条件中有一个失败时,就不能执行那些原本我们认为可以在失败的情况下执行的编码了,这是因为该程序极有可能会崩溃(图表B)。根据这种可能性,当一个契约式设计的前提条件或后置条件失败时,你需要这么做:
· 找出该契约中被破坏的ASAP。要完成这一步,人们通常会通过用调试器强行进入那些难缠的编码。
· 确保不执行那些被破坏的契约后面的编码不被执行(这是因为该程序可能会崩溃或产生无效的结果)。人们通常会通过抛出一个异常来完成这一步。
如果你正在开发一个应用程序,你可能更倾向于使用调试的方法,这是因为当一个错误出现时,你一定想立刻就知道。这会很有用,尤其是在从一个大的应用程序中连接不同的模块的时候(综合测试)。
当你开发一个库的时候,你从来都不知道会在哪儿用到它。例如,如果某个使用你的库的人要建一个服务器应用程序,调试器这一方法就行不通了;因此,抛出一个异常才是你的最佳选择。
调试器一法中存在的最大问题是,你的程序可能会在客户端崩溃。就因为这个原因,许多专家都建议大家选择第二种方法,而不是调试器。我也越来越赞成这些专家们的意见了,抛出一个异常会让你的程序更安全(图表C)。