24

I would like my BallUserInterfaceFactory to return an instance of a user interface that has the proper generic type. I am stuck in the example below getting the error:

Bound mismatch: The generic method getBaseballUserInterface(BASEBALL) of type BallUserInterfaceFactory is not applicable for the arguments (BALL). The inferred type BALL is not a valid substitute for the bounded parameter

public class BallUserInterfaceFactory { public static <BALL extends Ball> BallUserInterface<BALL> getUserInterface(BALL ball) { if(ball instanceof Baseball){ return getBaseballUserInterface(ball); } //Other ball types go here //Unable to create a UI for ball return null; } private static <BASEBALL extends Baseball> BaseballUserInterface<BASEBALL> getBaseballUserInterface(BASEBALL ball){ return new BaseballUserInterface<BASEBALL>(ball); } } 

I understand that it cannot guarantee that BALL is a Baseball, and so there is a parameter type mismatch on the getBaseballUserInterface method call.

If I cast the ball parameter in the getBaseballUserInterface method call, then I get the error:

Type mismatch: cannot convert from BaseballUserInterface<Baseball> to BallUserInterface<BALL>

Because it can't guarantee that what I am returning is the same type of BALL.

My question is, what is the strategy for dealing with this situation?

(For completeness, here are the other classes required in the example)

public class Ball { } public class Baseball extends Ball { } public class BallUserInterface <BALL extends Ball> { private BALL ball; public BallUserInterface(BALL ball){ this.ball = ball; } } public class BaseballUserInterface<BASEBALL extends Baseball> extends BallUserInterface<BASEBALL>{ public BaseballUserInterface(BASEBALL ball) { super(ball); } } 
2
  • Is BaseballUserInterface extends BallUserInterface<BaseBall> not enough? Do you have Subclasses of BaseballUserInterface? Commented Sep 27, 2012 at 19:34
  • @ollins I was using that strategy originally, if you change the example to that, you will end up with another "Type mismatch" situation because there is no guarantee that the BALL type returned from the factory is the same as the BALL type in the BallUserInterface. (This time specified in the BaseballUserInterface class declaration). Commented Sep 27, 2012 at 20:04

3 Answers 3

23

This is a wrong design pattern. Rather than using one generic method and an if ladder, you should instead use overloading. Overloading eliminates the need for the if ladder and the compiler can make sure the correct method is invoked rather than having to wait till runtime.

eg.

public class BallUserInterfaceFactory { public static BallUserInterface<Baseball> getUserInterface( Baseball ball) { return new BallUserInterface<Baseball>(ball); } public static BallUserInterface<Football> getUserInterface( Football ball) { return new BallUserInterface<Football>(ball); } } 

This way you also get the added benefit of compile time errors if your code cannot create a BallUserInterface for the appropriate ball.


To avoid the if ladder you can use a technique known as double dispatch. In essence, we use the fact that the instance knows what class it belongs to and calls the appropriate factory method for us. For this to work Ball needs to have a method that returns the appropriate BallInterface.

You can either make the method abstract or provide a default implementation that throws an exception or returns null. Ball and Baseball should now look something like:

public abstract class Ball<T extends Ball<T>> { abstract BallUserInterface<T> getBallUserInterface(); } 

.

public class Baseball extends Ball<Baseball> { @Override BallUserInterface<Baseball> getBallUserInterface() { return BallUserInterfaceFactory.getUserInterface(this); } } 

To make things a little neater, it's better to make getBallUserInterface package private and provide a generic getter in BallUserInterfaceFactory. The factory can then manage additional checks like for null and any thrown exceptions. eg.

public class BallUserInterfaceFactory { public static BallUserInterface<Baseball> getUserInterface( Baseball ball) { return new BallUserInterface<Baseball>(ball); } public static <T extends Ball<T>> BallUserInterface<T> getUserInterface( T ball) { return ball.getBallUserInterface(); } } 

The Visitor Pattern

As pointed out in the comments, one problem of the above is it requires the Ball classes to have knowledge of the UI, which is highly undesirable. You can, however, use the visitor pattern, which enables you to use double dispatch, but also decouples the various Ball classes and the UI.

First, the necessary visitor classes, and factory functions:

public interface Visitor<T> { public T visit(Baseball ball); public T visit(Football ball); } public class BallUserInterfaceVisitor implements Visitor<BallUserInterface<? extends Ball>> { @Override public BallUserInterface<Baseball> visit(Baseball ball) { // Since we now know the ball type, we can call the appropriate factory function return BallUserInterfaceFactory.getUserInterface(ball); } @Override public BallUserInterface<Football> visit(Football ball) { return BallUserInterfaceFactory.getUserInterface(ball); } } public class BallUserInterfaceFactory { public static BallUserInterface<? extends Ball> getUserInterface(Ball ball) { return ball.accept(new BallUserInterfaceVisitor()); } // other factory functions for when concrete ball type is known } 

You'll note that the visitor and the factory function have to use wildcards. This is necessary for type safety. Since you don't know what type of ball has been passed, the method cannot be sure of what UI is being returned (other than it is a ball UI).

Secondly, you need to define an abstract accept method on Ball that accepts a Visitor. Each concrete implementation of Ball must also implement this method for the visitor pattern to work correctly. The implementation looks exactly the same, but the type system ensures dispatch of the appropriate methods.

public interface Ball { public <T> T accept(Visitor<T> visitor); } public class Baseball implements Ball { @Override public <T> T accept(Visitor<T> visitor) { return visitor.visit(this); } } 

Finally, a bit of code that can put all this together:

Ball baseball = new Baseball(); Ball football = new Football(); List<BallUserInterface<? extends Ball>> uiList = new ArrayList<>(); uiList.add(BallUserInterfaceFactory.getUserInterface(baseball)); uiList.add(BallUserInterfaceFactory.getUserInterface(football)); for (BallUserInterface<? extends Ball> ui : uiList) { System.out.println(ui); } // Outputs: // ui.BaseballUserInterface@37e247e2 // ui.FootballUserInterface@1f2f0ce9 
Sign up to request clarification or add additional context in comments.

6 Comments

I really like this answer, but here is the issue I have with it: If I have a Ball then I cant call getUserInterface without putting an if ladder somewhere else. For instance: Ball ball = new Baseball(); BallUserInterface<?> ui = BallUserInterfaceFactory.getUserInterface(ball); Does not work because there could be other types of Ball that are not overloaded in the factory method.
@FuryComptuers But if you only have a Ball, you don't need the additional information a generic method will give you. You can just receive BallUserInterface<?>.
I added a bit about using double dispatch to avoid if ladders.
An object should not have any information about its User Interface, so adding a UI return method to the object is not the correct solution.
I should also add that it isn't even reasonable to assume that someone building a UI for a Ball object has the ability to change the Ball object. (though a wrapper could be created client-side)
|
3

This is a VERY GOOD question.

You could cast brutely

 return (BallUserInterface<BALL>)getBaseballUserInterface((Baseball)ball); 

The answer is theoretically flawed, since we force BASEBALL=Baseball.

It works due to erasure. Actually it depends on erasure.

I hope there is a better answer that is reification safe.

2 Comments

IMHO that cast is safe, despite the warning. With reification, wouldn't the cast be checked at runtime and presumably always work?
It is unfortunate, but this seems to be the only solution that doesn't move the problem somewhere else in the code.
0
public class BaseballUserInterface extends BallUserInterface<Baseball> { public BaseballUserInterface(Baseball ball) { super(ball); } } 

You are using the BallUserInterface as a result of the factory method. So, it can be hidden which concrete ball is used:

public class BallUserInterfaceFactory { public static BallUserInterface<?> getUserInterface(Ball ball) { if(ball instanceof Baseball){ return getBaseballUserInterface((Baseball)ball); } return null; } private static BaseballUserInterface getBaseballUserInterface(Baseball ball){ return new BaseballUserInterface(ball); } } 

If the client is interested in the type of the ball you should offer a factory method with the concrete ball as parameter:

public static BaseballUserInterface getUserInterface(Baseball ball){ return new BaseballUserInterface(ball); } 

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.