当前位置:主页 > 188金宝慱亚洲体育真人正文

188金宝慱亚洲体育真人:用标记区别对象类型会导致误贴标签

05月07日作者:黑曼巴


内容:

Impostor Type 差错模式

症状

治疗和预防步伐

着末阐明

总结

参考资料

关于作者

对本文的评价

用标记差别工具类型会导致误贴标签

Eric E. Allen (eallen@cs.rice.edu)

博士钻研生,Java 编程说话小组,Rice 大年夜学

2001 年 7 月

当应用字段中特殊的标记来差别工具类型时,会孕育发生标记对相关数据误贴标签的差错 ? 被称为 Impostor Type 差错模式。在诊断 Java 代码的这一部分中,Eric Allen 对这个差错的症状和原由188金宝慱亚洲体育真人进行了阐发,具体阐清楚明了预防差错孕育发生的措施,并评论争论了一种吸惹人的混杂实现措施,这种措施不应用 impostor type,但着末,照样有很多相同的毛病孕育发生。请在评论争论论坛与作者和其他读者分享您对本文的见地。

法度榜样中除了最无关紧要的部特别都要对某些数据类型进行操作。静态类型系统供给了一种措施,它能够确保法度榜样不会对给定类型的数据进行欠妥的操作。Java 说话的优点之一是严格的区分类型,以是在法度榜样运行前已打消了类型差错。作为开拓职员,我们可以应用这个类型系统供给更壮实且没有差错的代码。然而,我们却经常没有让类型系统发挥出最大年夜的潜力。

Impostor Type 差错模式

很多法度榜样可以更多地应用静态类型系统,但它们没有这样做,而是依附包孕差别数据类型标记的特殊字段。

代码快速跟踪

清单 1. 用 impostor type 实现几何外形

一个基础示例,演示了引入这类差错是若何的易如反掌。

清单 2. 构造新的 form

引入了差错。

清单 3. 用实际类型实现 form

这种新颖的措施可以在运行时报错。

清单 4. 一种混杂的实现要领

不应用 impostor type,但易受性一样。

寄托这些特殊字段差别数据类型,这样的法度榜样放弃了类型系统专门供给给它们的保护步伐。当这些标记中的一个对它的数据误贴了标签,就会孕育发生我称之为 Impostor Type 的差错。

症状

impostor type 差错的一种常见症状是很多观点上不合类型的数据都被同样(并且差错)的要领处置惩罚。另一常见症状是数据与任何指定的类型都不匹配。

重要规则是,只要当观点上的数据类型和它被法度榜样处置惩罚的措施不匹配,就可以狐疑是否发生了这个模式的差错。

为阐明引入这种模式的差错是多么的易如反掌,让我们来斟酌一个简单的示例。假设我们必要处置惩罚各类各样的欧几里得几何学外形,如圆形、正方形等等。这些几何外形没有坐标,但含有一个 scale 变量,以是可以谋略它们的面积。

清单 1. 用 imposter type 实现各类几何外形

public class Form {

String shape;

double scale;

public Form(String _shape, double _scale) {

this.shape = _shape;

this.scale = _scale;

}

public double getArea() {

if (shape.equals("square")) {

return scale * scale;

}

else if (shape.equals("circle")) {

retu188金宝慱亚洲体育真人rn Math.PI * scale * scale;

}

else { // shape.equals("triangle"), an equilateral triangle

return scale * (scale * Math.sqrt(3) / 4);

}

}

}

只管您会发明人们常常这么做,但用这种措施实现几何外形照样存在严重毛病。

最显明的毛病之一是这个措施不能真正的扩展。假如要为我们的 form 引入一个新的几何外形(比如,“五边形”),我们必须进入并改动 getArea() 措施的源代码。不过可扩展性是个自力的斟酌身分;在本文中,我们把重点放在实现几何外形所造成的差错的易受性上。我会在今后的文章中回到关于可扩展性的问题上来。

假如我们在法度榜样其它部分构造了一个新的 Form 工具,如下所示,请斟酌将会发生什么环境:

清单 2. 构造一个新的 form

Form f = new Form("sqaure", 2);

当然,“square”被拼错了,然则编译器觉得,这是完全合法的代码。

现在斟酌一下,当我们试图对新的 Form 工具调用,比如说 getArea() 措施时发生什么环境。由于 Form 工具中的几何外形与 if-then-else 代码块中的任一测试的几何外形都不匹配,它的面积将在 else 分句中被谋略,似乎它是个三角形似的!

这里将不会报错。事实上,在很多环境下,返回值看起来都好象是完全合理的数字。纵然我们插入些冗余代码,反省 else 分句中的隐含前提是否包孕(比如说,断言),也要到代码履行时才能发明差错。

很多其它相似的差错也可能在上述代码中孕育发生。if-then-else 代码块可能会有时漏掉一句分句,导致类型与那句分句相对应的所有 Form 都被差错地188金宝慱亚洲体育真人处置惩罚了。此外,由于 impostor type 在字段中只是一个 String,以是它可188金宝慱亚洲体育真人能会被意外或恶意地改动。

无论用哪一种措施,这样的改动会带来各类各样的侵害。

治疗和预防步伐

正如您可能设想过的那样,我建议用类型系统在静态反省时代将它们清除,从而避免这种类型的差错。请斟酌这种新颖的实现措施:

清单 3. 用实际类型实现 form

public abstract class Form {

double scale;

public Form(double _scale) {

this.scale = _scale;

}

public abstract double getArea();

}

class Square extends Form {

public Square(double _scale) {

super(_scale);

}

public double getArea() {

return scale * scale;

}

}

class Circle extends Form {

public Circle(double _scale) {

super(_scale);

}

public double getArea() {

return Math.PI * scale * scale;

}

}

class Triangle extends Form {

public Triangle(double _scale) {

super(_scale);

}

public double getArea() {

return scale * (scale * Math.sqrt(3) / 4);

}

}

现在斟酌一下,在创建一个新 Form 时,假如误输入了“Sqaure”,会发生什么环境。编译器将会报错,奉告我们类 Sqaure 找不到。代码将连运行的时机也没有。

同样地,编译器将不会容许我们忘怀为我们的随意率性质类定义 getArea() 措施。当然,任何工具要改变 Form 的类型是弗成能的。

着末阐明

在脱离这个主题之前,我还想评论争论另一种可能的实现,一种我曾经评论争论过的两种实现措施的混杂。

在这种环境下,不应用 impostor type,但代码包孕很多相同的易受性,彷佛它们曩昔就有。实际上,这种实现措施比对每个类型零丁实现 getArea() 措施更差。

清单 4. 一种混杂的实现要领

public abstract class Form {

double scale;

public Form(double _scale) {

this.scale = _scale;

}

public double getArea() {

if (this instanceof Square) {

return scale * scale;

}

else if (this instanceof Circle) {

return Math.PI * scale * scale;

}

else { // this instanceof Triangle

return scale * (scale * Math.sqrt(3) / 4);

}

}

}

class Square extends Form {

public Square(double _scale) {

super(_scale);

}

}

class Circle extends Form {

public Circle(double _scale) {

super(_scale);

}

}

class Triangle extends Form {

public Triangle(double _scale) {

super(_scale);

}

}

只管编译器仍然会捕获类型的拼写差错,且工具类型是无法改变的,我们又一次应用了 if-then-else 代码块调整适当的类型。这样,我们又要面临 if-then-else 代码块中 instanceof 反省与我们所操作的那组类型不匹配的环境。

还必须提出,像第一种实现措施那样,这个实现措施的扩展性不如第二种。

总结

那么,简而言之,这便是我们近来的差错模式:

模式:Impostor Type

症状:一种法度榜样,它用同样的要领处置惩罚观点上不合类型的数据,或者无法识别某种类型的数据。

原由:法度榜样针对各类类型的数据应用带标记的字段,而不是自力的类。

治疗和预防步伐:尽可能将观点上不合的数据类型分成几个自力的类。

重点在于,这种说话为您供给了避免这类差错的最好资本 ? 只是要记得应用它们。

参考资料

请介入本文的评论争论论坛。

JUnit 主页供给了很多有趣文章的链接,这些文章评论争论了法度榜样测试的措施,还有最新的 JUnit 版本。

假如您爱好 JUnit,请查看整套 xUnit 测试对象,有多种不合说话版本。

我必须提一下对象中的 xUnit 套件是设计用来和极度编程一路应用的,这是一种新型的功能强大年夜并快速开拓干净、壮实软件的措施。

“框架体系布局的 UML 概要文件”(PDF 幻灯片放映)凸起显示具体的 JUnit 个案钻研。

只管与这个评论争论没有直接的联系,我照样保举您参阅 Martin Fowler 的文章,此中评论争论了 UML 的角色和极度编程中的设计。

采纳 “Java 调试”教程(developerWorks,2001 年 2 月),从而得到一样平常调试技巧的赞助。

不认识 Java 开拓或盼望重温 Java 编程技巧吗?请采纳这篇周全的教程,“ Java 说话的根基常识”。

请涉猎 Eric 的所有诊断 Java 代码的文章,许多篇着重评论争论差错模式。

请在 developerWorks Java 技巧专区中查阅更多 Java 参考资料。

关于作者

Eric Allen 卒业于 Cornell 大年夜学,曾得到谋略机系和数学系的学士学位。他照样 Rice 大年夜学 Java 编程说话小组的博士188金宝慱亚洲体育真人钻研生。它的钻研涉及到开拓用于 Java 说话的语义模型和静态阐发对象,两者都是源代码和字节码级其余。今朝,他正在为 NextGen 编程说话实现一种从源代码到字节码的编译器,这也是 Java 说话的泛型运行时类型的一种扩展。请经由过程 eallen@cs.rice.edu 与他联系。

最近关注

热点内容

更多