5
\$\begingroup\$

This is a subtle question about design in which I want to find the most elegant and appropriate solution.

I have an enumeration representing a French card deck (see code below). With it I need to do certain things, such as displaying the elements in a table. I'll want to display the elements starting with ACE (the highest) down to deuce. The problem is that I don't want my UI part of the code to know which one is the highest and use a descending iterator. Should I have a method in my enumeration, something like "EnumSet descending()" ? I don't want to initialise the constants with integers that indicates their values, since in poker the cards don't have a numerical value per se, just an order. Probably it's just fine if users of this enum are supposed to know that an ACE has the highest value and display values accordingly to what they want, but just wondering if there is a better solution.

public enum Rank {
    DEUCE ("2"), 
    THREE ("3"), 
    FOUR ("4"), 
    FIVE ("5"), 
    SIX ("6"), 
    SEVEN ("7"), 
    EIGHT ("8"), 
    NINE ("9"), 
    TEN ("10"), 
    JACK ("J"), 
    QUEEN ("Q"), 
    KING ("K"), 
    ACE ("A");

    private String symbol;

    Rank (String symbol ) {
        this.symbol = symbol;
    }

    /**
     * Returns a string representation of this rank which is the full name 
     * where the first letter is capitalised and the rest are lowercase
     */
    @Override public String toString () {
        //only capitalize the first letter
        String s = super.toString();
        return s.substring (0, 1).toUpperCase() + s.substring(1).toLowerCase();
    }

    public String getSymbol () {
        return this.symbol;
    }
}
\$\endgroup\$
3
\$\begingroup\$

I think you should add a numeric field indicating the order of a card relative to the other cards. You do not need to use it for anything other than sorting.

Also, instead of taking the identifier of the enum value and doing uppercase and lowercase tricks with it in order to turn it into something presentable to the user, you should just store the name, too, as a separate string in the enum.

So, it would look like this: ACE( "A", "Ace", 0 ) (where 0 indicates lowest order for sorting.)

Furthermore you can also add one more number, the 'weight' of a card, to use in calculations which determine whether a card beats another. In general, enums in java are very powerful, so powerful that you pretty much end up not having to use the switch statement with enums anymore, because you can include a big part of an enum's functionality within the enum itself.

\$\endgroup\$
  • \$\begingroup\$ Thanks for the answer Mike. However I'm not sure about adding a numerical field for sorting. Enum provides you with the sorting and comparison capability already. It would feel like you are stepping over the Enum mechanisms, but, on the other hand, it would indicate explicitly which element is the greatest, so there might be a point in doing it that way. \$\endgroup\$ – DPM Jan 8 '12 at 21:34
1
\$\begingroup\$

One way to do it:

Rank[] values = Rank.values();
for (int i = values.length - 1; i >= 0; i--)
  ... values[i];

However that is slightly dangerous because it relies on the implicit ordering you used in the declaration.

Otherwise:

for (Rank rank : Rank.getBackwardIterator())
  ... rank

where in Rank:

private List<Rank> backwardList = Arrays.asList(ACE, ..., TWO); 

public Iterator<Rank> getBackwardIterator() {
   return backwardList.iterator();
}

On a more general note, cards really do have an ordering. You are using it to print them out backward, but I guess you'll use the ordering in many other places, so you should probably do as was suggested by Mike Nakis and put a hard numerical value in Rank. Alternatively, you can just make sure you define the cards are declared in the right order and make use of the default (enum.compareTo()).

\$\endgroup\$
  • \$\begingroup\$ Hi toto2, thanks for your answer. Cards do have an order but it's not so clear about numerical values (in poker). It's not a very important question and it's a very small nuance, but it would seem a breach of encapsulation knowing which one is the highest and which one is the lowest. I like that idea of adding a method with an explanatory name. That is a good solution. Not "getBackward" possibly, but something like "fromHighest", or similar. \$\endgroup\$ – DPM Jan 16 '12 at 0:29
  • \$\begingroup\$ I'm not a poker specialist, but I think a pair of 3's beats a pair of 2's. It would just be natural for your enum to include that information. \$\endgroup\$ – toto2 Jan 16 '12 at 0:41
1
\$\begingroup\$

Probably not, because the value of the cards can vary from game to game. Some games treat ace as low, others treat ace as high. Blackjack lets the player choose whether to count an ace as 1 or 11, and all face cards as 10.

If you only intend to use this enum for a particular game, feel free to do whatever is pragmatic. However, if you intend to model playing cards in general, then avoid hard-coding assumptions into the enum itself.

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.