周期性泛型(尝试2) [英] cyclical generics (try 2)

查看:77
本文介绍了周期性泛型(尝试2)的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

第二次尝试这个问题(最初的代码不足以突出显示问题)



以下是无法编译的代码:

  interface Player< R, G延伸游戏> 
{
R takeTurn(G游戏);
}

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

抽象类AbstractGame< R,P扩展播放器>
实现游戏< P>
{
public final void play(final P player)
{
final R value;

value = player.takeTurn(this);
turnTaken(价值);
}

保护抽象void turnTaken(R值);
}

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

public class XGame< P extends Player< Integer,XGame>>
扩展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)
{
最终的XPlayer播放器;
最终XGame游戏;

player = new XPlayer();
game = new XGame();
game.play(player);


$ / code>

我碰到的是试图获得在AbstractGame中的播放方法进行编译。看起来,我必须在游戏和玩家的圈子中运行,并将泛型添加到扩展/实现中,但对于我来说,我无法直接获得它。



play方法在AbstractGame类中必须是最终的,并且没有办法进行投射,并且我不想编写像turnTaken之类的其他方法来让它在我不需要的情况下工作。



编辑:按照这里的要求编译代码,但需要强制转换:

 接口Player< R,P扩展Player< R,P,G>,G extends Game< R,G,P>> 
{
R takeTurn(G游戏);
}

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

abstract class AbstractGame ,P extends Player >
实现游戏< R,G,P>
{
public final void play(final P player)
{
final R value;

value = player.takeTurn((G)this);
turnTaken(价值);
}

保护抽象void turnTaken(R值);
}

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);




$ {
public static void main(final String [] argv)
{
final XPlayer播放器;
最终XGame游戏;

player = new XPlayer();
game = new XGame();
game.play(player);
}
}


解决方案

混合泛型和原始类型不起作用。如果你需要这些接口互相引用,他们还需要引用自己:

  interface Player< R,P extends Player< R,P,G>,G延伸游戏< R,G,P>> 
{
R takeTurn(G游戏);
}

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

虽然这看起来相当有毛病,但我不确定为什么你需要它。



编辑: 我能够实现<$ c

 抽象类抽象游戏 

AbstractGame< R,P extends Player< R,P,AbstractGame< R,P>>>
实现Game< R,AbstractGame< R,P>,P>
{
public final void play(final P player)
{
final R value;

value = player.takeTurn(this);
turnTaken(价值);
}

保护抽象void turnTaken(R值);
}

然而我无法用 XGame XPlayer

  public class XGame 
扩展AbstractGame< Integer,XPlayer> //编译XPlayer的错误
{

protected void turnTaken(Integer value){}
}

public class XPlayer
implements Player< ; Integer,XPlayer,XGame> //编译XGame的错误
{
@Override
public Integer takeTurn(final XGame game)
{
return(42);




$ b $ p
$ b

这个问题似乎是每个通用声明 XGame XPlayer 需要另一个是正确的。这是您的设计真正具有周期性的地方。如果编译器'假设'每一个都是正确的,那理论上就是可行的。但它不会。



编辑2:



 界面游戏< R,G扩展游戏< R,G>> 
{
void play(Player< R,G> player);
}

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

抽象类AbstractGame< R,G扩展AbstractGame< R,G>>
实现游戏< R,G>
{
public final void play(final Player< R,G> player)
{
final R value;

value = player.takeTurn(self());
turnTaken(价值);
}

protected abstract G self();

保护抽象无效turnTaken(R值);
}

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);




$ b $ p
$ b

这里的关键是声明一个抽象方法<$ c在 AbstractGame 中返回一个 G 类型的实例的$ c> self()。扩展类必须用它们自己的类型来解析继承的类型参数,并实现 self()来返回 this 。这仅适用于内部代码,因为扩展类可能很容易说谎,例如:

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

查看我的回答此处此发布了解此模式的更多详情。


Second attempt at this question (the initial code wasn't enough to highlight the issue)

Here is the code that does not compile:

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);
    }
}

What I am running up against is trying to get the play method in the AbstractGame to compile. It seems that I have to run in circles with the Game and the Player adding generics to the extends/implements but for the life of me I cannot get it straight.

The play method has to be final in the AbstractGame class, and there is no way to do casting, and I don't want to write another method like the turnTaken one to get it to work if I don't have to.

EDIT: as requested here is the code that compiles, but needs the cast:

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);
    }
}

解决方案

Mixing generics and raw types isn't going to work. If you need these interfaces to reference each other, they also need to reference themselves:

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);
}

Although this is looking rather hairbrained, and I'm not sure why you need it.

Edit:

I was able to implement your AbstractGame based on the above:

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);
}

However I couldn't quite close the circuit with XGame and XPlayer:

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);
    }
}

The issue seems to be that each of the generic declarations of XGame and XPlayer needs the other to be correct. This is where your design is truly cyclical. If the compiler 'assumed' each was correct, it would in theory work. But it doesn't.

Edit 2:

How about this:

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);
    }
}

The key here was declaring an abstract method self() in AbstractGame that returns an instance of type G. Extending classes must resolve the inherited type parameter with their own type, and implement self() to return this. This is only suitable for internal code, since an extending class could easily lie, for example:

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

See my answer here and this post for more details on this pattern.

这篇关于周期性泛型(尝试2)的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆