简体   繁体   中英

2 way coupling of generics in java

sorry about the title I couldn't explain it in one sentence better!

so here is the problem, I'm making a small Card games engine in java, I'm trying to define the interfaces for the games to be as generic as possible

so I have these interfaces

public interface Card
{
     //some methods
}
public interface CardGame<TCard extends Card,TPlayer extends Player>
{
     //example method
     TPlayer getPlayerByName(String name);
}
public interface Player<TCardGame extends CardGame>
{
     //HERE IS THE ISSUE
     List<TCard> getCards();
}

the issue is in the last interface, I want to force a player to return the same type of cards of the game that is he is a generic of

in other words, Player<BannaCardGame> , should have List<BananCards>

but I can't find the right syntax to do this, TCard inside the Player interface has no meaning

so how can I achieve this behaviour ?

First, you might want to rethink whether you really need that. But not knowing why you might need it etc. here's some advice on how you could tackle your question:

Don't tie Player to CardGame but tie both to Card :

public interface Card {}

public interface CardGame<TCard extends Card,TPlayer extends Player<TCard>> {
 //example method
 TPlayer getPlayerByName(String name);
}

public interface Player<TCard extends Card> {     
 List<TCard> getCards();
}

Now you're only allowed to define a CardGame that uses matching implementations of Player and Card .

But again, I'm not sure that design is good (why should a player instance depend on the type of cards?) but since we don't know your requirements and why you decided to design it that way it's hard to give much advice on that (and it might be out of scope for SO anyways) so I'll leave this for you.

Edit:

From your comments it seems you also want to add getGame() to your Player interface (note for future questions: add that to the question as well, otherwise it might be missed).

You could define that method like this (I'll include the interface for completeness):

public interface Player<TCard extends Card> {     
  List<TCard> getCards();

  CardGame<TCard, ? extends Player<TCard>> getGame();
}

This would mean the player can return (belong to?) any game that uses the right type of card and any type of player declared for that type of card.

If you want to further restrict this, you could extend your interfaces (maybe that's what you're actually after):

//for the changes on TPlayer see the comment on Player
public interface CardGame<TCard extends Card,TPlayer extends Player<TCard, TPlayer>> {
  //example method
  TPlayer getPlayerByName(String name);
}

//Require the implementations to register themselves as generic types
public interface Player<TCard extends Card, TPlayer extends Player<TCard, TPlayer>> {     
  List<TCard> getCards();

  CardGame<TCard, TPlayer> getGame();
}

A BananaCard game could then look like this:

class BananaPlayer implements Player<BananaCard, BananaPlayer> {
  public List<BananaCard> getCards() { /*snip*/ }

  public CardGame<BananaCard, BananaPlayer> getGame() { /*snip*/ } 
}

class BananaGame implements CardGame<BananaCard, BananaPlayer> {
  public BananaPlayer getPlayerByName( String pName ) { /*snip*/ }    
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM