我有一个数据模型,其中包含一些从单个接口派生的类,如下所示:
public interface Foo extends Visitable {}
public class BarA implements Foo {
void accept(Visitor visitor) {
visitor.visit(this);
}
}
public class BarB implements Foo {
void accept(Visitor visitor) {
visitor.visit(this);
}
}
...
还有一个Visitor
有一些方法可以对数据模型的类做一些事情:
public class ModelVisitor implements Visitor {
String visit(Foo foo) {
// ...
}
String visit(BarA bar) {
// ...
}
String visit(BarB bar) {
// ...
}
// ...
}
说,我收到了Foo
类型的集合,迭代它们的元素并调用visit()
:
void run(List<Foo> fooList) {
for(Foo foo : fooList) {
// here is the question
foo.visit();
}
}
我如何决定调用哪个visit()
方法,因为它们都是foo的子类?我有两个可能的想法:
instanceof
并投射到正确的类型,但我想避免这种情况,因为我会在很多if
,else if
条件下结束。switch-case
语句中使用字符串比较的原因。示例:
String visit(List<Foo> fooList) {
for(Foo foo : fooList) {
switch(foo.getClass().getName()) {
case "BarA":
visit((BarA) foo);
break;
case "BarB":
visit((BarB) foo);
break;
// ...
}
}
}
在我看来,第二种方法看起来比使用instanceof
更清晰,但反射速度很慢。我的JVM知识不是那么好,但我假设instanceof
也会使用反射来获取对象的类型,因此两种解决方案之间没有真正的性能差异。
您会使用什么或有其他方法来解决这个问题?
答案 0 :(得分:0)
在访客模式中,您可以调用
foo.accept(visitor);
具体的Foo
对象然后决定调用哪个Visitor
方法。您不需要instanceof
。
例如,我删除了一些接口以使代码更小。
public class Main {
public static void main(String[] args) {
Bar bar1 = new BarA();
Bar bar2 = new BarB();
Visitor visitor = new Visitor();
bar1.accept(visitor);
bar2.accept(visitor);
}
public static class Bar {
public void accept(Visitor visitor) {
visitor.visit(this);
}
}
public static class BarB extends Bar {
public void accept(Visitor visitor) {
visitor.visit(this);
}
}
public static class BarA extends Bar {
public void accept(Visitor visitor) {
visitor.visit(this);
}
}
public static class Visitor {
public void visit(Bar bar) {
System.out.println("visited: Bar");
}
public void visit(BarA bar) {
System.out.println("visited: BarA");
}
public void visit(BarB bar) {
System.out.println("visited: BarB");
}
}
}
运行示例将输出
visited: BarA
visited: BarB
答案 1 :(得分:0)
只要Foo数组中的每个对象都使用其明确的构造函数创建,就不需要其中任何一个。我认为代码解释得更好:
使用您的代码的客户端应该如下创建Foo列表:
ArrayList<Foo> list = new ArrayList<Foo>();
list.add(new BarA());
list.add(new BarB());
...
这就是你所需要的一切。调用方法visit()
并传递“list”中的一个对象时,它将通过正确的方法。这是polimorphism的魔力。
如果您想确定,请继续打印您的清单:
for(Foo f : list)
System.out.println(f);
该类的名称将被打印出来,您将看到每个对象的引用都转到它的类而不是Foo: package.BarA@wholebunchfnumbers
尽管如此,我认为你仍然没有访客模式的概念。