Questions about the Visitor pattern (sample in Java)
The visitor pattern is just double dispatch.
I'm not sure I agree with your implementation of a visitor. I'd implement something like this:
interface MammalVisitor {
void visit(Pirate pirate);
void visit(Human human);
void visit(Dog dog);
}
// Basic visitor provides no-op behaviour for everything.
abstract class MammalAdapter implements MammalVisitor {
void visit(Pirate pirate) {};
void visit(Human human) {};
void visit(Dog dog) {};
}
And then the implementation would become cleaner:
// We only want to provide specific behaviour for pirates
class WoodLegCounterVisitor extends MammalAdaptor {
private int woodLegNumber = 0;
@Override
public void visit(Pirate pirate) {
woodLegNumber += pirate.getWoodLegNumber();
}
public int getWoodLegNumber() { return woodLegNumber; }
}
In answer to your actual question, the main advantage of using the visitor is avoiding the need to do the "instanceof" checks. It gives you the ability to separate out the logic for processing a hierarchy into a separate class. It also gives you the ability to add new behaviour without changing the original classes.
Visitor pattern is a fancy switch case / pattern matching system to facilitate graph traversal.
As typical functional languages offer pattern matching and efficient ways to traverse graphs, interest is much more limited.
Even in JAVA, with instanceof
or using enum
, a visitor is more of a fancy way to perform things than a generic solution as many algorithms will not fit well into it.
The purpose of the Visitor Pattern is to separate the object structure (in your case, Mammal
) from the algorithm (in your case, the counter Leg counter algorithm).
The whole idea is that your object (mostly in java, JavaBeans) doesn't change its structure at all, and only a new virtual function is introduced to introduce a new algorithm.
Unlike Jeff Foster's implementation, One can use Generics to make code easier. This brings specificity to your visitor, e.g.:
public interface MammalVisitor<T extends Mammal> {
public void visit(T mammal);
}
public class LegCounterVisitor implements MamalVisitor<Human> {
private int legNumber = 0;
@Override
public void visit(Human mammal) { legNumber += mammal.getLegsNumber(); }
public int getLegNumber() { return legNumber; }
}
public class WoodLegCounterVisitor implements MamalVisitor<Pirate> {
private int legNumber = 0;
@Override
public void visit(Pirate mammal) {legNumber += mammal.getWoodLegNumber(); }
public int getLegNumber() { return legNumber; }
}