My goal is to have an abstract Game class, whose constructor accepts a GameEngine that is suitable for derived Game classes. This abstract Game class will implement generic methods that are suitable for all Game implementations. You can think of the GameEngine as fulfilling a strategy pattern, to which Game delegates methods.
Therefore, upon creating a Game with a GameFactory, I don't care what implementation of Game the factory returns. I just want to make sure that the Game implementation gets constructed with the appropriate GameEngine implementation. However, if I simply return the raw type Game from the factory, I of course get Raw use of parameterized class 'Game' warnings.
Furthermore, ideally, the GameFactory.createGame(settings) method should not have to pass a type, but simply infer the type based on some property of settings.
This is the gist of the code I have:
public abstract class GameEngine<T extends Game<T>> {
public void doSomethingAllEnginesUnderstand(T game);
}
public class LocalGameEngine
extends GameEngine<LocalGame> {
}
public class RemoteGameEngine
extends GameEngine<RemoteGame> {
}
public abstract class Game<T extends Game<T>> {
private final GameEngine<T> gameEngine;
protected Game(GameEngine<T> gameEngine) {
this.gameEngine = gameEngine;
}
protected abstract T getSelf();
public final void doSomethingAllEnginesUnderstand() {
gameEngine.doSomethingAllEnginesUnderstand(getSelf());
}
}
public class LocalGame
extends Game<LocalGame> {
public LocalGame(LocalGameEngine gameEngine) {
super(gameEngine);
}
@Override
protected LocalGame getSelf() {
return this;
}
}
public class RemoteGame
extends Game<RemoteGame> {
public RemoteGame(RemoteGameEngine gameEngine) {
super(gameEngine);
}
@Override
protected RemoteGame getSelf() {
return this;
}
}
public class GameFactory {
// returns raw type Game
public Game createGame(GameSettings settings) {
if(settings.totalPlayers() > 1) {
return new RemoteGame(new RemoteGameEngine());
}
else {
return new LocalGame(new LocalGameEngine());
}
}
}
Am I misusing/misunderstanding generics to reach my stated goal? Is it possible to not make Game a generics class, while still mandating that an appropriate GameEngine implementation is passed to the constructor?
I feel you overuse the generics and I find
Game<T extends Game<T>>an overkill. I'd design it in this way:Make
LocalGameandRemoteGameextendsGame(no generic type). Use polymorphysm when you@OverridethegetSelfmethod:Make
LocalGameEngineandRemoteGameEngineextendsGameEngine(no generic type)Make
Gamerequire any subclass ofGameEngine, the generic part can be used in the constructor only, you don't need to make the wholeGamegeneric (Game<T>).The whole
GameFactorybecomes simplified: