Reputation: 4845
I have a collection of classes, call them Derived1, Derived2, ..., Derived6
, each of which is a subclass of a base class Base
. These classes are defined in a third-party Java package.
I'm writing a class that will write out a human-readable representations of these objects. I approached the problem as follows: define methods String transform(Derivedi object)
, for each i=1,2,...,6
, and String transform(Base object)
.
The problem occurs when, for example, Base obj = new Derived3(...)
and I want to compute the representation for obj
. The expression transform(obj)
invokes the method with signature String transform(Base)
, which has to call the "right" method (in this case the one with the signature String transform(Derived3)
).
The method String transform(Base object)
delegates work to the appropriate method via a sequence of conditional statements of the form if (obj instanceof Derivedi)
for each i=1,2,...,6
. (If I had control over the package I would have an abstract method String toReadable()
on the base class, which every derived class would have to implement; unfortunately in this case I have no control over the package.)
I don't like this solution (it's easy to see why). What would be the alternatives to this implementation of String transform(Base)
?
Upvotes: 0
Views: 207
Reputation: 88747
You could try and provide transformers (the objects that contain transform(...)
) per class. Then maintain a map that maps the transformers to those classes (assuming the transformers themselves are stateless).
Example:
class Transformer {
Class<? extends Base> getTransformableClass() { ... }
String transform( Base obj ){
//check and cast obj to the actual type then create the string
}
}
Map<Class<?>, Transformer> transformers = ...;
Transformer base = new BaseTransformer(); //the same for derived
transformers.put( base.getTransformableClass(), base );
Note that with CDI/Reflection you could do the lookup somewhat automatically (i.e. lookup all classes that implement a certain interface or are annotated with a certain annotation).
Then use it like this:
public String transform( Base obj) {
//add null checks etc.
return transformers.get(obj.getClass()).transform(obj);
}
Further note that generics might help when implementing the transformers but using them from the map would then make some casts/raw types necessary since you'd not know the actual type you get from the map, i.e. you as the developer know that transformers.get( Derived1.class )
should return a transformer being able to handle Derived1
instances but the compiler doesn't know that and thus needs you to handle that and cast appropriately.
Upvotes: 1
Reputation: 343
You can use getSimpleName() to get the name of the class, and use a switch statement on the name. You will still need this delegation to be done in transform(Base object)
but is will be somewhat cleaner than several if statements and instanceof checks.
Upvotes: 0