Java equals, когда равенство не может быть определено

Мне интересно, какова правильная парадигма программирования Java для переопределения методов equalshashCode) объекта класса C в случаях, когда либо (a) недостаточно информации, чтобы определить, равны ли два экземпляра C, или (b) вызывающий метод не должен быть в состоянии определить, равны ли два экземпляра C.

В моем проекте, например, есть класс PlayingCard. Мне кажется, что если PlayingCardлежит лицом вверх, то вызывающие методы должны иметь доступ к его свойствам, а если лицом вниз, то эти свойства должны оставаться неизвестными:

class PlayingCard {
    private Rank rank;
    private Suit suit;
    private boolean isFaceDown;

    public PlayingCard(Rank rank, Suit suit, boolean isFaceDown) {
        this.rank = rank;
        this.suit = suit;
        this.isFaceDown = isFaceDown;
    }

    public Rank getRank() { return isFaceDown ? null : rank; }

    public Suit getSuit() { return isFaceDown ? null : suit; }

Похоже также, что для ради Java Collections Framework две игральные карты должны быть равны, если они имеют одинаковый ранг и масть:

    public boolean equals(Object obj) {       // attempt #1
        if(this == obj) return true;
        if(obj == null) return false;
        if(!(obj instanceof PlayingCard)) return false;
        PlayingCard other = (PlayingCard) obj;
        if(rank != other.rank) return false;
        if(suit != other.suit) return false;
        return true;
    }
 }

Но это раскрывает слишком много информации:

class Malicious {

    public Rank determineRankOfFaceDownCard(PlayingCard faceDownCard) {
        Set<PlayingCard> allCards = /* a set of all 52 PlayingCards face up */;
        for(PlayingCard c : allCards) {
            if(c.equals(faceDownCard)) {
                return c.getRank();
            }
        }
        return null;
    }
}

Использование методов getRankи getSuit` тоже не работает:

    public boolean equals(Object obj) {       // attempt #1
        if(this == obj) return true;
        if(obj == null) return false;
        if(!(obj instanceof PlayingCard)) return false;
        PlayingCard other = (PlayingCard) obj;
        if(getRank() != other.getRank()) return false;
        if(getSuit() != other.getSuit()) return false;
        return true;
    }
}

/* outside the PlayingCard class */

Set<PlayingCard> s = new HashSet<PlayingCard>();
s.add(new PlayingCard(Rank.ACE, Suit.SPADES, true));
s.contains(new PlayingCard(Rank.TWO, Rank.HEARTS, true)); // returns true

Как другие разработчики справились с этой ситуацией? Является ли это ситуацией, когда было бы уместно бросить какое-то RuntimeException? Спасибо за любой вклад и идеи.

12
задан Radu Murzea 19 June 2012 в 15:33
поделиться