簡體   English   中英

循環泛型(試2)

[英]cyclical generics (try 2)

第二次嘗試這個問題(初始代碼不足以突出問題)

這是不編譯的代碼:

interface Player<R, G extends Game>
{
    R takeTurn(G game);
}

interface Game<P extends Player>
{
    void play(P player);
}

abstract class AbstractGame<R, P extends Player>
    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);
}

public class XPlayer
    implements Player<Integer, XGame>
{
    @Override
    public Integer takeTurn(final XGame game)
    {
        return (42);
    }
}

public class XGame<P extends Player<Integer, XGame>>
    extends AbstractGame<Integer, XPlayer>
{
    @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方法進行編譯。 似乎我必須在游戲和玩家的圈子中運行擴展/實現的泛型,但對於我的生活我不能直截了當。

play方法必須在AbstractGame類中是最終的,並且沒有辦法進行轉換,並且我不想編寫另一個方法,如turnTaken,如果我不需要它可以使它工作。

編輯:這里要求的是編譯的代碼,但需要演員:

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

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

abstract class AbstractGame<R, G extends Game<R, G, P>, P extends Player<R, P, G>>
    implements Game<R, G, P>
{
    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<Integer, XPlayer, XGame>
{
    @Override
    public Integer takeTurn(final XGame game)
    {
        return (42);
    }
}

class XGame
    extends AbstractGame<Integer, XGame, XPlayer>
{
    @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);
    }
}

混合泛型和原始類型是行不通的。 如果您需要這些接口相互引用,它們還需要引用自己:

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

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

雖然這看起來很像頭發,但我不確定你為什么需要它。

編輯:

我能夠基於以上內容實現您的AbstractGame

abstract class AbstractGame<R, P extends Player<R, P, AbstractGame<R, P>>>
    implements Game<R, AbstractGame<R, P>, 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<Integer, XPlayer> //compile error on XPlayer
{

    protected void turnTaken(Integer value) { }
}

public class XPlayer
    implements Player<Integer, XPlayer, XGame> //compile error on XGame
{
    @Override
    public Integer takeTurn(final XGame game)
    {
        return (42);
    }
}

問題似乎是XGameXPlayer每個通用聲明XPlayer需要另一個是正確的。 這是您的設計真正具有周期性的地方。 如果編譯器“假定”每個都是正確的,那么它在理論上是可行的。 但事實並非如此。

編輯2:

這個怎么樣:

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

interface Player<R, G extends Game<R, G>>
{
    R takeTurn(G game);
}

abstract class AbstractGame<R, G extends AbstractGame<R, G>>
    implements Game<R, G>
{
    public final void play(final Player<R, G> 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<Integer, XGame>
{
   protected XGame self() {
      return this;
   }

   protected void turnTaken(Integer value) { }
}

public class XPlayer implements Player<Integer, XGame>
{
    @Override
    public Integer takeTurn(final XGame game)
    {
       return (42);
    }
}

這里的關鍵是在AbstractGame中聲明一個抽象方法self() ,它返回一個G類型的實例。 擴展類必須使用自己的類型解析繼承的類型參數,並實現self()以返回this 這僅適用於內部代碼,因為擴展類很容易存在,例如:

public class EvilGame extends AbstractGame<Integer, AnotherGame> { ... }

有關此模式的更多詳細信息,請參閱此處此帖子中的答案。

正如Paul Bellora指出的那樣,你正在混合通用和原始類型 - 正確的,完全通用的解決方案有點混亂,需要大量的冗余。 在Java中使用循環(但不是遞歸)泛型沒有很好的方法(我知道)。

我不會在這方面苦苦掙扎,而是只使用一個參數,即播放的值的類型 - PlayerGame通用性 - 你有什么作為R

interface Game<R> {
    void play(Player<? extends R> player);
}

interface Player<R> {
    R takeTurn(Game<? super R> game);
}

abstract class AbstractGame<R> implements Game<R> {
    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<Integer> {
    @Override
    public Integer takeTurn(Game<? super Integer> game) {
        return 42;
    }
}

class XGame extends AbstractGame<Integer> {
    @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的游戲。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM