Solution: A Second Order

Comparable gave Card one order, and that order is built into the type. The previous section showed that compareTo could just as well have compared suit first and rank second; either order is valid, so the choice between them just depends on what you need. But Card has only one compareTo, so it can only hold one order at a time. Say we keep rank first as the natural order, and also want to group a hand by suit, so all the clubs are grouped together, then the diamonds, and so on. That second order cannot live inside Card alongside the first, so it has to come from outside, as a Comparator.

Solution

A Comparator<Card> is a separate class with one method, compare(a, b), that returns the same negative / zero / positive answer compareTo would return. The difference is that the rule is defined outside Card.

public class SuitComparator implements Comparator<Card> {

  @Override
  public int compare(Card a, Card b) {
    if (a.getSuit() != b.getSuit()) {
      return Character.compare(a.getSuit(), b.getSuit());
    }
    return Integer.compare(a.getRank(), b.getRank());
  }
}

Notice that SuitComparator reads the cards only through their public getters. It does not depend on Card’s internals, and Card never mentions SuitComparator. You can write a separate comparator for each order you want, and Card stays as it is.