按合约设计与依赖巧合编程

前端之家收集整理的这篇文章主要介绍了按合约设计与依赖巧合编程前端之家小编觉得挺不错的,现在分享给大家,也给大家做个参考。
任何程序库都有自己的一套使用方法,你只有严格遵守程序库设计者定义的规范下,才能‘随意’的使用他。

比如在STL中,除了Vector之外的大多数容器的Iterator都不能被存储,因为针对容器的很多操作都会导致Iterator失效,只有在每次使用Iterator时都从容器中重新获得才可以保证安全,否则“行为未定义”。(当然Iterator的使用也不至于如此死板,但这样的使用一定是最简单最合法的,如果法律规定写反革命文章要砍头,我不知道什么是反革命,可我知道什么是写文章,为了不被砍头于是我不写文章,前提是我并不是个作家)

又如在Java中,java.util.Vector类的add方法,add方法有一个两个参数的重载版本

add(int index,E element);

可用来在容器的指定位置插入element,但是index的值必须在0到size()之间。

这就是一个规则,如果你打破规则,对于STL来说会发生“未定义的行为”,对Java来说会给你一个ArrayIndexOutOfBoundsExecption,如果你没有很好的处理,那么这依然是个未定义的行为。

所谓学习一个程序库的过程就是学会这个程序库所规定的规则。你学会的东西包括
1. 按一定的顺序调用库中的某些函数。eg. SDL 中你必须 SDL_Init 先,最后还要 SDL_Destory.
2. 你调用函数时所传给的每个参数的意义及限制。eg. 上面java.util.Vector.add的index.
3. 调用函数所能产生的结果。

所有上面这些东西都不能通过程序(指接口)本身说明,只有文档(包括注释)可以。

任何一个程序库都必有自己的规则,或者说合约,一个库设计者和库使用者签订的合约。

不存在没有规则的程序库,或者说不存在没有合约的程序。

所以永远不要试图把你的程序库/类/函数/或者随便什么东西,设计成全能的,Vector的add方法就是不能接受index=-1,不必要非要让他接受。

对于Snow中的setActiveDocument方法,按合约设计时是这样的:

/**

* @pre containsDocument(doc) == true

* @post getActiveDocument() == doc

*/

void setActiveDocument(Document doc) {

activeDocument_ = doc;

}


但是在实现时为了避免/提醒用户不要依赖巧合编程。我们应该实现成这样:

void setActiveDocument(Document doc) {

assert(containsDocument(doc)) : "active document must in the document list";

activeDocument_ = doc;

}

上面两者并不冲突,第一种程序是设计时存在于脑中的 Design Code,而第二种程序是编码时的 Implement Code. 除此之外还存在一种按合约编程,可以利用某种工具帮助我们直接将 Design Code 转变为 Implement Code,在这样的工具下我们只需要将 Design Code 写出即可。

猜你在找的设计模式相关文章