1

I am trying to achieve the best potential of OOP in Java by creating a blackjack game. I have 5 java files so far.

Suit.java

enum Suit {

/*
 * Initialize suit values
 */
    HEARTS,
    SPADES,
    CLUBS,
    DIAMONDS;
}

Rank.java

enum Rank {

    /*
     * Initialize rank and card value
     */

    TWO(2),
    THREE(3), 
    FOUR(4), 
    FIVE(5), 
    SIX(6),
    SEVEN(7), 
    EIGHT(8), 
    NINE(9), 
    TEN(10), 
    JACK(10), 
    QUEEN(10),
    KING(10), 
    ACE(11);


    // Hold card value
    private int cardValue;

    /*
     * Constructor set card value
     * @param cardValue value of card
     */
    private Rank(int cardValue) {
        this.cardValue = cardValue;
    }

    /*
     * This method obtains the card value
     * @return This returns the value of card
     */
    public int getCardValue() {
        return cardValue;
    }
}

Card.java

public class Card {

    private Suit suit;
    private Rank rank;


    public Card(Rank rank, Suit suit) {
        this.rank = rank;
        this.suit = suit;
    }

    public Rank getCardValue() {
        return rank;
    }

    public Suit getSuitValue() {
        return suit;
    }
}

deck.java

import java.util.ArrayList;
import java.util.Collections;
import java.util.Random;


public class Deck {

    private ArrayList deck;

    public Deck() {

        this.deck = new ArrayList();

        for(Suit suit : Suit.values()) {
            for(Rank rank: Rank.values()) {
                Card card = new Card(rank, suit);
                this.deck.add(card);
            }
        }

        Collections.shuffle(deck);
    }

    public ArrayList getDeck() {
        return deck;
    }
}

Game.java

import java.util.ArrayList;
import java.util.Iterator;

public class Game {

    public static void main(String[] args) {

        Deck deck = new Deck();

        for(int i=0; i<deck.getDeck().size(); i++) {

            System.out.println( ((Card)   deck.getDeck().get(i)).getCardValue() + " of " 
            + ((Card) deck.getDeck().get(i)).getSuitValue() );
        }
    }
}

Does my design make sense so far? Also how can I call (Rank.java) -> int getCardValue() instead of (Card.java) -> Rank getCardValue()? Do I need to do some polymorphism? extend? I want the int value not the text value.

Thanks!

martijnn2008
  • 3,552
  • 5
  • 30
  • 40
Zahidul Islam
  • 99
  • 1
  • 9
  • 1
    This may not be an appropriate question for this site. Having said that, how are you going to handle the potential dual values of the ACE rank, 1 and 11? – Hovercraft Full Of Eels Jul 07 '16 at 12:46
  • 3
    Yes indeed a better place for this question is [codereview.SE.com](http://codereview.stackexchange.com/) – martijnn2008 Jul 07 '16 at 12:48
  • 1
    As for getting the Rank, simply use `getRank()` and call `getValue()` on the object returned.... or whatever name you give these methods. – Hovercraft Full Of Eels Jul 07 '16 at 12:49
  • 2
    Use generics: `ArrayList` in your class `Deck`, instead of the [raw type](http://stackoverflow.com/questions/2770321/what-is-a-raw-type-and-why-shouldnt-we-use-it) `ArrayList`. – Jesper Jul 07 '16 at 13:21

2 Answers2

2

To answer your direct question, all you need to do is to simply chain methods:

Card myCard = new Card(Rank.TWO, Suit.HEARTS);
int value = myCard.getCardValue().getCardValue();

The first getCardValue() call returns a Rank object, and the next getCardValue() get's the rank's value. But this is confusing to me, two methods with the same name that return different types. Myself, I'd rename Card's getCardValue() to be the more straightforward and logical getRank() and Rank's getCardValue() to the more simple getValue(). Then the code would look more logical:

int value = myCard.getRank().getValue();

As for your other question, "is the design OK", that's too broad for this site, but I think that you're using inheritance fine, that you don't want to over-use inheritance and to stick with composition as you're doing. And also I will say that you need to account for ACE having two possible values, 1 and 11.

For example, possibly something like:

public enum Rank {

    TWO(2, 0, false), 
    THREE(3, 0, false), 
    FOUR(4, 0, false), 
    FIVE(5, 0, false), 
    SIX(6, 0, false), 
    SEVEN(7, 0, false), 
    EIGHT(8, 0, false), 
    NINE(9, 0, false), 
    TEN(10, 0, false), 
    JACK(10, 0, false), 
    QUEEN(10, 0, false), 
    KING(10, 0, false), 
    ACE(11, 1, true);

    private int value;
    private int value2;
    private boolean twoValues;

    private Rank(int value, int value2, boolean twoValues) {
        this.value = value;
        this.value2 = value2;
        this.twoValues = twoValues;
    }

    public int getValue() {
        return value;
    }

    public int getValue2() {
        // TODO: consider throwing a custom exception if twoValues is false
        return value2;
    }

    public boolean hasTwoValues() {
        return twoValues;
    }
}
Hovercraft Full Of Eels
  • 283,665
  • 25
  • 256
  • 373
1

Just to throw some alternatives out there: I would perhaps model the value of a rank differently. Since the ace doesn't really have a definite value. A Hand has a value, but even that actually has a "best value", that may count an ace 11 or 1.

So I would perhaps remove the value of a rank. And introduce a Hand:

public class Hand {
    private Hand(Collection<Card> cards) {
        ...
    }

    private int calculateBestValue() {
        ...
    }
}

I would also not make the value calculation public. The Hand could "present" itself, so it can also say whether you have a "soft" value or not.

I also think the Deck should not have a getDeck() method. That violates encapsulation. Instead it should a method called: nextCard(). Which gives you the next card from the top of the deck. It may need an isEmpty() method too, which returns whether the deck has cards or not.

Robert Bräutigam
  • 7,514
  • 1
  • 20
  • 38