I have a set of classes that all need to be acted on in some (individual) way.
Ordinarily I’d just create a DoSomethingInterface with a single doSomething() method and have each class implement that method in a way that suits each class’ needs. However, I cannot do that in this case as the class definitions are unmodifyable (auto-generated)
So, I reckon I need to create a set of different classes that each take one of the autogenerated classes and performs the operation on them. So, say I have 2 autogenerated classes, Class1 and Class2, I will first define a common Operator interface:
public interface Operator <TYPE>{
public void doSomething(TYPE type);
}
and then implement one of these per class
public class Class1Operator implements Operator<Class1>{
public void doSomething(Class1 type){
...
...
}
}
and
public class Class2Operator implements Operator<Class2>{
public void doSomething(Class2 type){
...
...
}
}
Ok, so far so good. Now, given that I have an object of type Class1, is there any way of getting its operator without resorting to:
public Operator getOperator(Object obj){
if(obj instanceof Class1){
return new Class1Operator();
}else if(obj instanceof Class2{
return new Class2Operator();
}
return null;
}
Which kinda seems like bad practice to me…
The only other way I can think of is by creating a map of operators to class names like so:
Map<Class, Operator> allOperators = new HashMap<Class, Operator>();
allOperators.put(Class1.class, new Class1Operator());
allOperators.put(Class2.class, new Class2Operator());
and then return the operator using:
public Operator getOperator(Object obj){
return allOperators.get(obj);
}
But this doesn’t seem right (I’m not sure, are there any issues with keying an object off its class….)
Any input as to whether either of these approaches is ‘correct’? or is there a more elegant solution??
Thanks
What you’ve implemented (the map-by-class approach) is one of the alternatives to the GoF Visitor pattern I talk about when I teach patterns. It’s efficient and extendable, even at runtime. Much better than the if/else if/else hardwired approach.
The only issue with keying off the class is if the actual instances implement subtypes rather than the class type you mention; then the lookup map won’t work.
If you need subtypes to be recognized, I’d recommend Aaron’s approach (walk up the superclass chain), but you may also want to look at implemented interfaces as well. If you just need “exact class match”, keep your getOperator simple.
Note that you have a bug in getOperator — it should look as follows:
One more thing… Hide your map inside another class and manage it as follows:
This prevents anyone from registering an operator that won’t work against the class it’s keyed against. (You might want to use Operator as the parameter to allow an operator that’s written against a superclass, but that’s might not be needed)