1

I am working on a party game in java.

I struggle to make a proper class hierarchy for cards. The player can carry cards. There are different kind of cards so I made for each card group a separate class. There are the following classes for cards:

  • Card (Superclass)
    • NumberedCard (Subclass of Card)
      • NumberedSpecialCard (Subclass of NumberedCard)
    • MasterCard (Subclass of Card)
      • WarriorMasterCard (Subclass of MasterCard)
      • ...

First I construct a NumberedSpecialCard:

NumberedSpecialCard firstPlayerThirdCard = new NumberedSpecialCard(13);

Next I add the card to a list (here firstPlayerCards)

List<Card> firstPlayerCards = new LinkedList<Card>();
firstPlayerCards.add(firstPlayerThirdCard);

Now I create a player object. The player can carry a list of cards.

Player firstPlayer = new Player(firstPlayerMumbles, firstPlayerCards, 1,"Player ONE");

The problem is that i can not access the 'bringMumbleIntoPlay' method which is defined in the NumberedSpecialCard class.

The following does not work:

firstPlayer.getCards().get(2).bringMumbleIntoPlay(allPlayers, firstPlayer, 1);

I do not want to change the class hierarchy (It pictures the real conditions very well.). Can someone help me?

  • Since you are [programming to an interface](https://stackoverflow.com/questions/383947/what-does-it-mean-to-program-to-an-interface), the method `bringMumbleIntoPlay` must be present in the `Card` class. – Thiyagu Jul 19 '20 at 09:15
  • 2
    This is not how inheritance works. Since you reference the `NumberedSpecialCard` through a `Card`-reference, you can only access the methods defined in `Card`. How can you be sure that the 3rd card (`firstPlayer.getCards().get(2)`) will be a `NumberedSpecialCard`? --- Please read: [Why is “Can someone help me?” not an actual question?](https://meta.stackoverflow.com/questions/284236/why-is-can-someone-help-me-not-an-actual-question) – Turing85 Jul 19 '20 at 09:16
  • Only objects of `NumberedSpecialCard` should be able to use the method: `bringMumbleIntoPlay`. If I change the `Card` class to a interface and add the method `public void bringMumbleIntoPlay();` in the `Card` interface would this not mean that I can use the method on all Objects which implements the `Card` interface? – JamalNewtron Jul 19 '20 at 09:25
  • 1
    @JamalNewtron yes, that is right. But again: how can you be sure that the 3rd card (`firstPlayer.getCards().get(2)`) is a `NumberedSpecialCard`? I mean... your code suggests that you are sure about this, question is why. There may be an easy solution to the problem, but we need more information wrt. the problem domain. – Turing85 Jul 19 '20 at 09:29
  • I think that I can not be sure what card the player will have at the third slot in his card list. Because later in a advanced state of the game the player will randomly receive 5 cards. These can be NumberedCard, NumberedSpecialCard or MasterCard. The NumberdSpecialCards have the numbers (1, 4, 7, 8 and 13) and the NumberedCards can only be (3, 5, 6, 9, 10 and 12). – JamalNewtron Jul 19 '20 at 09:36
  • 1
    So in this case... you cannot simply call `bringMumbleIntoPlay(...)` on any card since you do not know if the card is actually a `NumberedSpecialCard`. – Turing85 Jul 19 '20 at 09:39
  • Okay, I get it. Thank you for your input. Do you have a suggestion what I could do to get this done right? – JamalNewtron Jul 19 '20 at 09:43
  • @JamalNewtron I gave you the approach – Abhinaba Chakraborty Jul 19 '20 at 09:46

1 Answers1

0

firstPlayer.getCards() is a list of Cards. Now a Card does not have the method bringMumbleIntoPlay in it. So compiler has no idea which subclass it needs to look into. That's why it complains.

One alternative is to use explicit casting with a safety check using instanceof

Card c = firstPlayer.getCards().get(2);
if(c instanceof NumberedSpecialCard){
   NumberedSpecialCard  nsc = (NumberedSpecialCard)c; 
   nsc.bringMumbleIntoPlay(allPlayers, firstPlayer, 1);
}

Abhinaba Chakraborty
  • 3,488
  • 2
  • 16
  • 37
  • 4
    A typecast ist generally a code smell. The pressing question is how OP can be sure that the 3rd card will be a `NumberedSpecialCard`. – Turing85 Jul 19 '20 at 09:19
  • I will add a safer approach then. – Abhinaba Chakraborty Jul 19 '20 at 09:19
  • 1
    The typecast is at least a bad of a code smell since this is not really extensible. Again: the core question is how OP can be sure that the 3rd card will be a `NumberedSpecialCard`. I have a feeling that there is a much simpler solution (from the business logic perspective) to the problem. – Turing85 Jul 19 '20 at 09:22
  • @AbhinabaChakraborty Thank you for your reply. Since I do not know what the 3rd card will (could be NumberedSpecialCard, NumberedCard or MasterCard) I can not cast in advance. – JamalNewtron Jul 19 '20 at 09:49
  • @JamalNewtron you are not casting in advance. See that `if` check. It's the safeguard – Abhinaba Chakraborty Jul 19 '20 at 09:50
  • You can add other conditions for other types of Cards – Abhinaba Chakraborty Jul 19 '20 at 09:51