循环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); }
但是我无法用XGame
和XPlayer
关闭电路:
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); } }
问题似乎是XGame
和XPlayer
每个通用声明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没有很好的方法(我知道)。
我不会挣扎于此,而是只使用一个参数,即播放的值的类型 – Player
和Game
通用性 – 你有什么作为R
interface Game { void play(Player extends R> player); } interface Player { R takeTurn(Game super R> game); } abstract class AbstractGame implements Game { public final void play(Player extends R> 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 super Integer> 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
的游戏。