循环generics(试2)

第二次尝试这个问题(初始代码不足以突出问题)

这是不编译的代码:

interface Player { R takeTurn(G game); } interface Game

{ void play(P player); } abstract class AbstractGame implements Game

{ public final void play(final P player) { final R value; value = player.takeTurn(this); turnTaken(value); } protected abstract void turnTaken(R value); } public class XPlayer implements Player { @Override public Integer takeTurn(final XGame game) { return (42); } } public class XGame<P extends Player> extends AbstractGame { @Override protected void turnTaken(final Integer value) { System.out.println("value = " + value); } } public class Main { public static void main(final String[] argv) { final XPlayer player; final XGame game; player = new XPlayer(); game = new XGame(); game.play(player); } }

我正在遇到的是尝试在AbstractGame中编写play方法。 似乎我必须在游戏和玩家的圈子中运行扩展/实现的generics,但对于我的生活,我无法直截了当。

play方法必须在AbstractGame类中是最终的,并且没有办法进行转换,并且我不想编写另一个方法,如turnTaken,如果我不需要它可以使它工作。

编辑:这里要求的是编译的代码,但需要演员:

 interface Player<R, P extends Player, G extends Game> { R takeTurn(G game); } interface Game<R, G extends Game, P extends Player> { void play(P player); } abstract class AbstractGame<R, G extends Game, P extends Player> implements Game { public final void play(final P player) { final R value; value = player.takeTurn((G)this); turnTaken(value); } protected abstract void turnTaken(R value); } class XPlayer implements Player { @Override public Integer takeTurn(final XGame game) { return (42); } } class XGame extends AbstractGame { @Override protected void turnTaken(final Integer value) { System.out.println("value = " + value); } } class Main { public static void main(final String[] argv) { final XPlayer player; final XGame game; player = new XPlayer(); game = new XGame(); game.play(player); } } 

混合generics和原始类型是行不通的。 如果您需要这些接口相互引用,它们还需要引用自己:

 interface Player, G extends Game> { R takeTurn(G game); } interface Game, P extends Player> { void play(P player); } 

虽然这看起来很像头发,但我不确定你为什么需要它。

编辑:

我能够基于以上内容实现您的AbstractGame

 abstract class AbstractGame>> implements Game, P> { public final void play(final P player) { final R value; value = player.takeTurn(this); turnTaken(value); } protected abstract void turnTaken(R value); } 

但是我无法用XGameXPlayer关闭电路:

 public class XGame extends AbstractGame //compile error on XPlayer { protected void turnTaken(Integer value) { } } public class XPlayer implements Player //compile error on XGame { @Override public Integer takeTurn(final XGame game) { return (42); } } 

问题似乎是XGameXPlayer每个通用声明XPlayer需要另一个是正确的。 这是您的设计真正具有周期性的地方。 如果编译器“假定”每个都是正确的,那么它在理论上是可行的。 但事实并非如此。

编辑2:

这个怎么样:

 interface Game> { void play(Player player); } interface Player> { R takeTurn(G game); } abstract class AbstractGame> implements Game { public final void play(final Player player) { final R value; value = player.takeTurn(self()); turnTaken(value); } protected abstract G self(); protected abstract void turnTaken(R value); } public final class XGame extends AbstractGame { protected XGame self() { return this; } protected void turnTaken(Integer value) { } } public class XPlayer implements Player { @Override public Integer takeTurn(final XGame game) { return (42); } } 

这里的关键是在AbstractGame中声明一个抽象方法self() ,它返回一个G类型的实例。 扩展类必须使用自己的类型解析inheritance的类型参数,并实现self()以返回this 。 这仅适用于内部代码,因为扩展类很容易存在,例如:

 public class EvilGame extends AbstractGame { ... } 

有关此模式的更多详细信息,请参阅此处和此post中的答案。

正如Paul Bellora指出的那样,你正在混合通用和原始类型 – 正确的,完全通用的解决方案有点乱,需要大量的冗余。 在Java中使用循环(但不是递归)generics没有很好的方法(我知道)。

我不会挣扎于此,而是只使用一个参数,即播放的值的类型 – PlayerGame通用性 – 你有什么作为R

 interface Game { void play(Player player); } interface Player { R takeTurn(Game game); } abstract class AbstractGame implements Game { public final void play(Player player) { final R value; value = player.takeTurn(this); turnTaken(value); } protected abstract void turnTaken(R value); } class XPlayer implements Player { @Override public Integer takeTurn(Game game) { return 42; } } class XGame extends AbstractGame { @Override public void turnTaken(Integer value) { System.out.println("value = " + value); } } public class Main { public static void main(String[] argv) { XPlayer player = new XPlayer(); XGame game = new XGame(); game.play(player); } } 

现在,任何知道如何采取基于R的动作的玩家都可以玩任何基于R的游戏。