Reputation: 1470
Below is my Transformer Interface
public interface Transformer<BusinessObject, O extends State>
{
public O transformToState(BusinessObject input);
}
This is one of my Transformer Impl
public class GoldTransformer implements Transformer<BusinessObject, Gold>
{
@Override
public Gold transformToState(BusinessObject input) {
GoldBO goldbo= (GoldBO) input; // redundant casting line
//do some transformation with BO to make it a state with some business logic
}
}
Here is my another Transformer Impl
public class SilverTransformer implements Transformer<BusinessObject, Sliver>
{
@Override
public Gold transformToState(BusinessObject input) {
SilverBO goldbo= (SilverBO) input; // redundant casting line
// again do some transformation with BO to make it a state with some business logic
}
}
Both SilverBO
and GoldBO
Implements BusinessObject
which is a marker interface. And Silver
and Gold
extend State
. I really find the casting annoying and redundant is there a better way to use generics here? or a better pattern to use? I don't want to make any changes to state
i.e. gold and silver.
Upvotes: 3
Views: 70
Reputation: 44200
It looks like BusinessObject is a class, but you're also using the same identifier as a generic type parameter! In this code, BusinessObject does not refer to your class, it's a distinct identifier. If it's in a different package, you can verify this by verifying that it does not need to be imported.
interface Transformer<BusinessObject, O extends State>
{
public O transformToState(BusinessObject input);
}
This is semantically identical to:
interface Transformer<FlyingSpaghettiMonster, O extends State>
{
public O transformToState(FlyingSpaghettiMonster input);
}
Any decent IDE will colour generic type parameters differently to help you differentiate them. See below, the real type parameters are white, while the generic type parameters are dark green:
While you should change the generic type parameter to avoid confusion, all you technically need to do to remove the casting is change your transformer implementations like so:
public class GoldTransformer implements Transformer<GoldBO, Gold>
{ // ^ changed
@Override
public Gold transformToState(GoldBO input) {
// ^ changed
}
}
However, it's possible (or likely) that you'll also want to enforce that the first type parameter is a subclass of BusinessObject, otherwise it would be possible to create a Transformer<String, Gold>
. To do this, change your interface to:
public interface Transformer<I extends BusinessObject, O extends State>
{
public O transformToState(I input);
}
Where I
is now the generic type parameter and BusinessObject is a real type which does refer to your class.
Upvotes: 2
Reputation: 44456
Make the input generic as well:
public interface Transformer<I extends BusinessObject, O extends State> {
public O transformToState(I input);
}
Silver example:
public class SilverTransformer implements Transformer<SilverBO, Silver> {
@Override
public Silver transformToState(SilverBO input) {
return new Silver(input); // an example, perform the transformation...
}
}
Java 8 gives a shorter way
Alternatively, if you use Java 8 or higher, the Transformer<BusinessObject, O extends State>
does exactly the same as java.util.Function<BusinessObject, O extends State>
. Therefore the interface would be not needed. The usage is pretty neat:
Function<SilverBO, Silver> silverTransformer = (input -> new Silver(input));
Silver silver = silverTransformer.apply(silverBo);
Perform the transformation directly inside the lambda expression. If the transformation takes more lines, use the brackets {}
and return
.
Function<SilverBO, Silver> silverTransformer = (input -> {
Silver output = // transformation ...
// ... more transformation ...
return output;
});
Upvotes: 1
Reputation: 311853
You could generalize the interface on the input BusinessObject
too:
public interface Transformer<I extends BusinessObject, O extends State> {
public O transformToState(I input);
}
public class GoldTransformer implements Transformer<GoldBO, Gold> {
@Override
public Gold transformToState(GoldBO input) {
// Code...
}
}
Upvotes: 5