与许多通常不受欢迎的语言功能一样,通过实施一种以某种方式“伪造”它们的机制来欺骗使用它们通常很诱人。但这并没有使任何事情变得更好。如果您意思是测试对象的类型,那么instanceof 是正确的选择。如果你想避免它,你需要找到一种方法,而不是要求你找出对象的(动态)类型。
避免运行时类型检查的一种流行模式是使用 visitor 模式,该模式有效地使重载解决方案和动态调度机制完成了肮脏的工作。如果您的实际问题与您发布的博物馆示例一样简单,那么这显然是矫枉过正。无论如何,这是可以做到的。
为了这个例子,假设我们有Paintings 和Drawings,它们都派生自ArtObject。我们定义了一个抽象的访问者类型,它对每个ArtObject 都有一个方法。或者,您可以只专注于少数几个,并有一个备用的“访问任何东西”方法。
public abstract class ArtVisitor {
public void visit(final Painting painting) {
}
public void visit(final Drawing drawing) {
}
// public void visit(final ArtObject anything) {
// }
}
我使用了抽象类而不是接口,因此我可以使用 visit 方法的空默认实现。
在ArtObject 接口(或抽象类,就此而言)中,我们需要添加一个抽象takeVisitor 方法。
public abstract class ArtObject {
private final String name;
protected ArtObject(final String name) {
this.name = name;
}
public abstract void takeVisitor(ArtVisitor visitor);
@Override
public final String toString() {
return String.format("%s (%s)",
this.name,
this.getClass().getCanonicalName());
}
}
不幸的是,我们无法实现 ArtObject.takeVisitor,因为this 指针将具有静态类型ArtVisitor,这需要我们进行类型自省,而这正是我们想要避免的。相反,我们必须——这是访问者模式最丑陋的地方——在我们的每个类中重写它。
(如果我们添加了备用ArtVisitor.visit(ArtObject) 方法,我们可以实现一个通用的takeVisitor 方法,但我们仍然必须在派生类中重写它以根据@987654336 的类型进行重载决策@ 指针起作用。在大多数情况下,这会增加更多的混乱(和潜在的错误)而不是好处。)
public final class Painting extends ArtObject {
public Painting(final String name) {
super(name);
}
@Override
public void takeVisitor(final ArtVisitor visitor) {
visitor.visit(this);
}
public void aMethodOnlyPaintingsHave() {
// whatever...
}
}
public final class Drawing extends ArtObject {
public Drawing(final String name) {
super(name);
}
@Override
public void takeVisitor(final ArtVisitor visitor) {
visitor.visit(this);
}
}
现在我们可以直接建造博物馆了。
import java.util.List;
import java.util.ArrayList;
public final class Museum {
private final List<ArtObject> artworks;
public Museum() {
this.artworks = new ArrayList<ArtObject>();
artworks.add(new Painting("Mona Lisa"));
artworks.add(new Drawing("Madame Palmyre with Her Dog"));
artworks.add(new Painting("The Night Watch"));
}
public void printAllWorks() {
for (final ArtObject work : this.artworks) {
System.out.println(work);
}
}
public void printAllPaintings() {
final ArtVisitor paintingsPrinter = new ArtVisitor() {
@Override
public void visit(final Painting painting) {
System.out.println(painting);
// Note: We don't need any unsafe downcast here!
painting.aMethodOnlyPaintingsHave();
}
};
for (final ArtObject work : this.artworks) {
work.takeVisitor(paintingsPrinter);
}
}
public static void main(final String[] args) {
final Museum myMuseum = new Museum();
System.out.println("All ArtObjects:\n");
myMuseum.printAllWorks();
System.out.println("\n\nAll Paintings:\n");
myMuseum.printAllPaintings();
}
}
上述程序的输出为:
All ArtObjects:
Mona Lisa (Painting)
Madame Palmyre with Her Dog (Drawing)
The Night Watch (Painting)
All Paintings:
Mona Lisa (Painting)
The Night Watch (Painting)