诊断Java代码: Broken Dispatch错误模式 - 编程入门网
n this.value.getFirst(); }
public LinkedList getRest() {
return new LinkedList(this.value.getRest());
}
public void push(String s) { this.value = new Cons(s, this.value); }
public String pop() {
String result = (String)this.value.getFirst();
this.value = this.value.getRest();
return result;
}
public boolean isEmpty() { return this.value instanceof Empty; }
public String toString() {...}
...
}
假设我们写了这些代码,并且所有的测试案例都可以正常运行。(或者,更现实些,假设它起初并不能正常运行,可经过几个调试周期后,我们使它变得能够正常运行了。) 也许几个月后,您开发了类 Cons 的一个新构造函数,它使用列表的 String 表达作为其唯一的参数。这种构造函数非常有用 ― 它允许我们用下面这样的表达式构造新的列表: 清单 3. 新构造函数仅使用列表的 String 表示法作为参数
这样,我们写了这个构造函数而且它的所有测试案例也正常运行了。太棒了!但是,接着,我们发现,太不可思议了,类 LinkedList 的方法测试中有一些突然中断了。发生了什么事? 诊断Java代码: Broken Dispatch错误模式(3)时间:2011-02-12 IBM Eric E. Allen起因 问题在于类 LinkedList 的构造函数,它只有一个 String 作为参数。 这个构造函数以前曾调用底层的类 Cons 的构造函数。但是,既然我们用一个更加明确的方法 ― 该方法只有一个 String 作为参数 ― 重载了这个构造函数,那么被调用的就是这个更加特殊的方法了。 除非传递给 LinkedList 构造函数的 String 是一个有效的 Cons 表示法,否则试图对其进行语法分析时就会导致程序崩溃。更糟糕的是,如果 String 正好是一个有效的 Cons 表示法,程序就会使用这些毁坏的数据继续执行。如果那样的话,我们就在数据中引入了一个破坏者数据。关于破坏者数据的讨论,请参阅最后一部分,“ 破坏者数据错误模式”。 Broken Dispatch 错误,与所有的错误模式一样,在“布满测试”的代码(借用自极端编程术语)中最容易诊断,在这种环境中连最微不足道的方法也有相应的单元测试。在这样的环境里,最为一般的症状是为您从未碰过的代码编写的测试案例突然中断运行。 如果这种情况发生,有可能是 Broken Dispatch 模式的一种情况。如果测试案例中断是在您重载另一个方法后立即发生的,那就几乎可以肯定。 如果这段代码没有经过布满测试,情况就变得更加困难了。错误症状可能表现为,比如,返回速度比预期快得多(并且结果错误)的方法调用。换句话说,您可能会发现本来应该发生的某些事件从未发生(因为正确的方法未曾被执行)。 要记住,尽管类似的症状也可能是其它错误模式的缘故。但是,如果遇到这种的症状,最好是开始写更多的单元测试,从发现错误的方法开始,回退测试程序执行的过程。 治疗和预防措施 关于这个错误模式的好消息是有一些简单的解决方案。最直接的一种方法是把方法调用中的参数 上溯造型。在我们的示例中,这意味着重写相关的 LinkedList 构造函数,如下所示: 清单 4. 在方法调用中上溯造型参数
当然,这种办法只解决了调用 Cons 构造函数这个问题。还有其它地方的调用,我们也得上溯造型,这种技术对于 Cons 类的客户来说是很讨厌的。在这样的情形下,您就得权衡一下,应用这个方便的构造函数给您带来的好处以及它引入错误的潜在危险,二者孰重孰轻了。 接口的表达性和健壮性之间的平衡也存在这种 |
凌众科技专业提供服务器租用、服务器托管、企业邮局、虚拟主机等服务,公司网站:http://www.lingzhong.cn 为了给广大客户了解更多的技术信息,本技术文章收集来源于网络,凌众科技尊重文章作者的版权,如果有涉及你的版权有必要删除你的文章,请和我们联系。以上信息与文章正文是不可分割的一部分,如果您要转载本文章,请保留以上信息,谢谢! |