Is the following java implementation of the visitor pattern using generics, general enough to be useful? (I suppose it is).
Could it be improved in some way? It's important to be easily call-able using anonymous classes. Thanks.
(Example of use):
Vector<Number> numbers = new Vector<Number>();
numbers.add(new Double(1.2));
numbers.add(new Float(-1.2));
numbers.add(new Double(4.8));
numbers.add(new Float(-3.4));
numbers.add(new Long(123456));
numbers.add(new Short("14"));
For.each(numbers, new Visitor<Number>() {
public void doIt(Double n) {
System.out.println("doIt() for double: " + n);
}
public void doIt(Float n) {
System.out.println("doIt() for float: " + n);
}
public void doIt(Number n) {
System.out.println("doIt() for Number: " + n);
}
});
Visitor<Number> visi = new Visitor<Number>() {
private StringBuffer all = new StringBuffer ();
public void doIt(Number n) {
System.out.println("doIt() for Number: " + n);
all.append(n.toString() + " ");
}
public Object getResult () {
return all;
}
};
For.each(numbers, visi);
System.out.println ("all -> " + visi.getResult());
Definitions:
//............................................
abstract class Visitor<T> {
public void visit(T n) {
try {
this.getClass().getDeclaredMethod("doIt", n.getClass()).invoke(this, n);
} catch (Exception ex) {
doIt((T) n);
}
}
public void doIt(T n) {
System.out.println("doIt() for base " + n);
}
public Object getResult() {
return null;
}
} // class
//............................................
class For {
public static <T> void each (Collection<T> c, Visitor<T> f) {
for (T v : c) {
f.visit(v);
}
} // ()
} // class
how about
This is not the Visitor Pattern.
Visitor is characterized by the visitee having an
accept(Visitor v)
method that interacts with an visit method in the visitor taking as parameter the visitee and overloaded for the varying type of the visitee, forming a "double dispatch" mechanism.Quoting from the "Applicability" section for Visitor in Design Patterns:
So this pattern is for dealing with similar opertaions on objects of multiple types. In your examples the objects you're calling visitors can only deal with one type.
In your answer revising to use reflection to handle multiple types (which by the way would be better done as an edit to the question or as a separate question), you're avoiding creating an
accept(Visitor v)
method in the visited classes by using reflection, which is to a degree accomplishing the same goal, but somewhat awkwardly. I still would resist calling it an implementation of Visitor.If code in the style you've written here is useful to you, by all means use it, but please don't call it a Visitor.
This is more like a Strategy Pattern or a Function Object, and if you rename the generic class in a way that reflects that, it's in fact useful, and your usage is similar to common patterns of list handling in functional languages.
What I would likely do with the code from the question is rename your
Visitor<T>
toOperation<T>
and rename yourvisit(T t)
toexecute(T t)
orapply(T t)
, thinking of anOperation
as aFunction
without a return value. I have in fact used exactly this in ways similar to what you're doing, and used similar tactics for collection "mapping" using genericFunction<Domain, Range>
objects. I'm not sure what pattern name actually fits it, but it's not Visitor. It's bringing functional list-comprehension style to an OO world where functions are not naturally first-class objects.Thanks to the answer of donroby about my initial code not implementing the visitor pattern I came to this new version.
I suppose it now implements the visitor pattern without the need of modifying the visited element with an accept() method. Anyway, it is able to call the right method depending on the element type (I guess that's the mission for the accept()), thanks to reflection.
First, an example of use:
That produces this output
And finally the code
}
}