visitor pattern in generics of Java
Make an visitor interface for an type, Entity. It has two generics types for return-type and optional parameter type.
interface EntityVisitor<T, K> {
T visit(Entity unknown, K args);
T visit(LongEntity source, K args);
T visit(StringEntity source, K args);
}
Let's say Entity is like this which has accept. Its signature is something a bit complicated because of two generics types.
abstract class Entity {
public <T, K> T accept(EntityVisitor<T, K> visitor, K args) {
return visitor.visit(this, args);
}
}
Entity's sub classes are like this. Make sure overriding accept method =) It's important to dispatch.
abstract class LongEntity extends Entity {
Long value; // snip constructor
public <T, K> T accept(EntityVisitor<T, K> visitor, K args) {
return visitor.visit(this, args);
}
}
abstract class StringEntity extends Entity {
String value; // snip constructor
public <T, K> T accept(EntityVisitor<T, K> visitor, K args) {
return visitor.visit(this, args);
}
}
And create a concrete visitor. It's like adding a new polymorphic method to Entity.
class Stringify implements EntityVisitor<String, Integer> {
public String visit(Entity unknown, Integer args) {
throw new IllegalStateException("unknown: " + unknown + " args:" + args);
}
public String visit(LongEntity source, Integer args) {
return "Long:" + source.value + " with " + args;
}
public String visit(StringEntity source, Integer args) {
return "String:" + source.value + " with " + args;
}
public static void main(String[] args) {
Entity a = new LongEntity(123L);
Entity b = new StringEntity("123");
System.out.println(new Stringify().visit(a, 3));
System.out.println(new Stringify().visit(b, 87));
}
}
Here is the result of execution.
$ java Stringify
Long:123 with 3
String:123 with 87