-1

I have a data model with some classes that are derived from a single interface, like this:

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);
    }  
}

...

Also there is a Visitor that has some methods for doing something with the classes of the data model:

public class ModelVisitor implements Visitor {

    String visit(Foo foo) {
            // ...
    }

    String visit(BarA bar) {
        // ...
    }

    String visit(BarB bar) {
        // ...
    }

    // ...
}

Say, I got a Collection of type Foo, iterate over their elements and call visit():

void run(List<Foo> fooList) {
    for(Foo foo : fooList) {
        // here is the question
        foo.visit();
    }
}

How do i decide which visit() method to call, because they are all subclasses of foo? I got two possible ideas:

  1. Use instanceof and cast to the correct type, but i would like to avoid that because i will end up in a lot of if, else if conditions.
  2. My other approach was to use reflection. The application will run in Java7, that's why i can use string comparison in switch-case statements.

example:

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;
        // ...
        }
    }
}

In my opinion the second approach looks cleaner than using instanceof, but reflection is known slow. My JVM knowledge isn't that good, but i assume that instanceof will also use reflection to get the type of the object, so there are no real performance differences between the two solutions.

What would you use or are there other ways to solve this problem?

klingt.net
  • 2,019
  • 3
  • 18
  • 19
  • 1
    You should rewrite your question like "How to switch a visitor method based on the type" or simply "How does the visitor pattern work" – René Link Dec 19 '13 at 16:24

2 Answers2

0

In the visitor pattern you call

foo.accept(visitor);

the concrete Foo object then decides which Visitor method to call. You don't need instanceof.

For example purpose I remove some interface to make the code a bit smaller.

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");
        }

    }

}

Running the example will output

visited: BarA
visited: BarB
René Link
  • 48,224
  • 13
  • 108
  • 140
  • That is right, but doesn't answer my question what to when you got a `List` f.e., where `BarA` and `BarB` are subclasses of `Bar`. – klingt.net Dec 19 '13 at 17:01
  • @klingt.net it's the same as if `BarA` and `BarB` implement `Foo`, except that you have to implement `accept(Visitor)` in `Bar` as well. But of course you can not implement the `acceptVisitor()` only in the `Bar` class and just extend `Bar`. That is not what the visitor pattern is about. The visitor pattern is based on polymorphism. See http://en.wikipedia.org/wiki/Visitor_pattern – René Link Dec 19 '13 at 17:07
  • @klingt.net I updated my answer with your Bar example as mentioned in the comment. – René Link Dec 19 '13 at 17:15
0

There's no need for either of those as long as each object in the Foo array has been created with its definite constructor. I think code explains better:

The client that uses your code should create the Foo list as such:

ArrayList<Foo> list = new ArrayList<Foo>();
list.add(new BarA());
list.add(new BarB());
...

That's all you need. When the method visit() gets called and passed one of the objects in "list" it will go through the proper method. It's the magic of polimorphism.

If you want to make sure, just go ahead and print out your list with:

for(Foo f : list)
System.out.println(f);

The name of the class will be printed out and you'll see that each object's reference goes to it's class rather than Foo: package.BarA@wholebunchfnumbers

Nonetheless I think you still don't have the concept of the visitor pattern down.

Chayemor
  • 3,577
  • 4
  • 31
  • 54