英文:
Avoid raw type warnings with a factory that returns a generic object implementing a strategy pattern
问题
我的目标是拥有一个抽象的 Game
类,其构造函数接受适用于派生的 Game
类的 GameEngine
。这个抽象的 Game
类将实现适用于所有 Game
实现的通用方法。你可以将 GameEngine
视为一个策略模式,Game
类将方法委托给它。
因此,在使用 GameFactory
创建一个 Game
时,我不关心工厂返回的 Game
实现是什么。我只想确保 Game
实现使用适当的 GameEngine
实现进行构造。然而,如果我简单地从工厂返回原始类型 Game
,当然会得到 Raw use of parameterized class 'Game'
的警告。
此外,理想情况下,GameFactory.createGame(settings)
方法不应该传递类型,而是根据 settings
的某个属性来推断类型。
以下是代码的主要部分:
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 {
public Game createGame(GameSettings settings) {
if (settings.totalPlayers() > 1) {
return new RemoteGame(new RemoteGameEngine());
} else {
return new LocalGame(new LocalGameEngine());
}
}
}
我是否误用/误解了泛型来实现我的目标?是否可能在仍然要求将适当的 GameEngine
实现传递给构造函数的情况下,将 Game
设置为非泛型类?
英文:
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?
答案1
得分: 1
我认为您过多地使用了泛型,并且我认为Game<T extends Game<T>>
有些过于繁琐。我会按照以下方式进行设计:
- 让
LocalGame
和RemoteGame
都继承自Game
(无泛型类型)。在您重写getSelf
方法时使用多态:
public class LocalGame extends Game {
public LocalGame(LocalGameEngine gameEngine) {
super(gameEngine);
}
@Override
protected LocalGame getSelf() {
return this;
}
}
public class RemoteGame extends Game {
public RemoteGame(RemoteGameEngine gameEngine) {
super(gameEngine);
}
@Override
protected RemoteGame getSelf() {
return this;
}
}
- 让
LocalGameEngine
和RemoteGameEngine
都继承自GameEngine
(无泛型类型):
// 实际上,这个抽象类可以是一个接口
public abstract class GameEngine {
public void doSomethingAllEnginesUnderstand(Game game) {}
}
public class LocalGameEngine extends GameEngine { }
public class RemoteGameEngine extends GameEngine { }
- 让
Game
要求任何GameEngine
的子类,泛型部分只需在构造函数中使用,无需将整个Game
定义为泛型(Game<T>
):
public abstract static class Game {
private final GameEngine gameEngine;
protected <T extends GameEngine> Game(T gameEngine) {
this.gameEngine = gameEngine;
}
protected abstract Game getSelf();
public final void doSomethingAllEnginesUnderstand() {
gameEngine.doSomethingAllEnginesUnderstand(getSelf());
}
}
- 整个
GameFactory
变得更简化:
public Game createGame(GameSettings settings) {
if (settings.totalPlayers() > 1) {
return new RemoteGame(new RemoteGameEngine());
} else {
return new LocalGame(new LocalGameEngine());
}
}
英文:
I feel you overuse the generics and I find Game<T extends Game<T>>
an overkill. I'd design it in this way:
-
Make
LocalGame
andRemoteGame
extendsGame
(no generic type). Use polymorphysm when you@Override
thegetSelf
method:public class LocalGame extends Game { public LocalGame(LocalGameEngine gameEngine) { super(gameEngine); } @Override protected LocalGame getSelf() { return this; } }
public class RemoteGame extends Game { public RemoteGame(RemoteGameEngine gameEngine) { super(gameEngine); } @Override protected RemoteGame getSelf() { return this; } }
-
Make
LocalGameEngine
andRemoteGameEngine
extendsGameEngine
(no generic type)// actuyally, this abstract class can be an interface instead public abstract class GameEngine { public void doSomethingAllEnginesUnderstand(Game game) {} }
public class LocalGameEngine extends GameEngine { }
public class RemoteGameEngine extends GameEngine { }
-
Make
Game
require any subclass ofGameEngine
, the generic part can be used in the constructor only, you don't need to make the wholeGame
generic (Game<T>
).public abstract static class Game { private final GameEngine gameEngine; protected <T extends GameEngine> Game(T gameEngine) { this.gameEngine = gameEngine; } protected abstract Game getSelf(); public final void doSomethingAllEnginesUnderstand() { gameEngine.doSomethingAllEnginesUnderstand(getSelf()); } }
-
The whole
GameFactory
becomes simplified:public Game createGame(GameSettings settings) { if (settings.totalPlayers() > 1) { return new RemoteGame(new RemoteGameEngine()); } else { return new LocalGame(new LocalGameEngine()); } }
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论