Мне интересно, какова правильная парадигма программирования Java для переопределения методов equals
(и hashCode
) объекта класса 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
? Спасибо за любой вклад и идеи.