I’m trying to create Java module with abstract code that further allows me to create different card games, like (Poker, Durak, Uno, etc.) The idea is to make code in module extensible and reusable. Code examples provided below:
/* Card */
public abstract class AbstractCard {
}
// Standard card
public final class StandardCard extends AbstractCard {
private final Suit suit;
private final Rank rank;
}
// I can introduce some other card. For example for Game Uno and etc.
/* Hand */
public abstract class AbstractHand<C extends AbstractCard> {
protected final List<C> cards;
protected HandState state;
}
// Common type of deck where you see all cards and you can choose which to use
public final class StandardHand<C extends AbstractCard> extends AbstractHand<C> {
public C getCard(int index) {
return cards.remove(index);
}
}
// You unable to see cards in your hand and only take the top one
public final class BlindHand<C extends AbstractCard> extends AbstractHand<C> {
public C getCard() {
return cards.remove(cards.size() - 1);
}
}
/* Deck */
public abstract class AbstractDeck<C extends AbstractCard> implements Iterable<C> {
private final List<C> cards;
private int index;
}
// Then I can have standard(unmodifiable) deck / modifiable(allows to add cards back to deck) deck / etc.
// Further, everywhere where I want to work with Abstract + Card/Hand/Deck (btw I have also
// Board and Table) I need to provide types, like this:
private final StandardTable<StandardCard, StandardHand<StandardCard>> table;
// Or passing in method:
default <C extends AbstractCard, H extends AbstractHand<C>, D extends AbstractDeck<C>> void splitCardsBetweenHands(D deck, List<H> hands) {
hands.forEach(hand -> {
while (hand.size() < 6 && deck.iterator().hasNext()) {
hand.addCard(deck.iterator().next());
}
});
}
// It results to complex method creation but gives a lot of flexibility
// but I feel that as my code grows I may encounter more nested constructions
// somehow I want to avoid that.
// I don't remember that any Java library provides example where you have to
// write type more than 2/3 times.
From my understanding I have 2 options to keep my code abstract:
- Keep using the same approach as above
- Instead of generics I can use Interfaces everywhere but then I will need to use casting and this will result to almost the same code.
Question is: I think I have issues with my code design but don’t understand why. Do I have any other options to keep my code abstract without mess with casting or providing type too many times?