[英]How to avoid instanceOf and dynamic getter check?
此代碼來自我在應用程序中使用的CardUtility
class。
public static boolean areBothColoredAndHaveSameColor(Card c1, Card c2) {
if (c1 instanceof ColoredCard coloredCard1 && c2 instanceof ColoredCard coloredCard2)
return coloredCard1.getColor() == coloredCard2.getColor();
return false;
}
public static boolean areBothNumberedAndHaveSameNumber(Card c1, Card c2) {
if (c1 instanceof NumberedCard numberedCard1 && c2 instanceof NumberedCard numberedCard2)
return numberedCard1.getNumber() == numberedCard2.getNumber();
return false;
}
public static boolean areBothSpecialAndHaveSameSpeciality(Card c1, Card c2) {
if (c1 instanceof SpecialColoredCard specialColoredCard1 && c2 instanceof SpecialColoredCard specialColoredCard2)
return specialColoredCard1.getSpeciality() == specialColoredCard2.getSpeciality();
return false;
}
我顯然可以看到這里發生的代碼重復,但我無法使用equals
檢查,並且由於 inheritance 層次結構: NumberedCard
和SpecialColoredCard
都擴展了抽象ColoredCard
class。 如何避免冗余? 我是否應該讓所有這些實現一個新的CardWithKeyProperty interface
並將這些方法重構為單個doBothHaveTheSameKeyProperty()
方法? 但是我再次不確定,因為ColoredCard
在 inheritance 層次結構中要高一級,所以它們都實現了相同的接口聽起來不正確。
就像評論中提到的那樣,inheritance 並不總是最好的解決方案。 使用 NumberedCard 和 ColoredCard 對這種情況進行建模並不是很有用。 因為彩色卡片總是有一個數字,而編號卡片總是有一個顏色,所以為什么要把這些概念分開。
我會創建兩個類。 一張為帶有顏色和編號的 NormalCard,另一張為 SpecialCard。 並且在接口卡中應該存在一個方法 compatibleTo()。
只是我的2c
Optional<Colour>
、 Optional<Integer>
等,這樣不具備該特性的卡就可以返回Optional.empty()
。然后您的代碼可能如下所示:
enum UnoColour {
RED, GREEN, YELLOW, BLUE
}
interface Card {
Optional<Integer> getNumber();
Optional<UnoColour> getColour();
}
public static boolean areBothColoredAndHaveSameColor(Card c1, Card c2) {
return compareCards(c1, c2, c -> c.getColour());
}
public static boolean areBothNumberedAndHaveSameNumber(Card c1, Card c2) {
return compareCards(c1, c2, c -> c.getNumber());
}
public static <T> boolean compareCards(Card a, Card b, Function<Card,Optional<T>> extractor) {
Optional<T> aValue = extractor.apply(a);
Optional<T> bValue = extractor.apply(b);
return aValue.isPresent() && bValue.isPresent() && aValue.get().equals(bValue.get());
}
所以compareCards
刪除了重復的代碼。
通過使用方法引用而不是顯式的 lambda,我們可以使代碼更加地道(盡管如果您不熟悉所使用的特性可能更難理解):
return compareCards(c1, c2, Card::getNumber);
並在compareCards
map
public static <T> boolean compareCards(Card a, Card b, Function<Card,Optional<T>> extractor) {
return extractor.apply(a)
.flatMap(at -> extractor.apply(b).map(bt -> at.equals(bt)))
.orElse(false);
}
您仍然可以為每種類型的卡使用子類,例如:
class ColouredCard implements Card {
private final Optional<UnoColour> colour;
ColouredCard(UnoColour colour) {
this.colour = Optional.of(colour);
}
@Override
public Optional<Integer> getNumber() {
return Optional.empty();
}
@Override
public Optional<UnoColour> getColour() {
return colour;
}
}
在編譯時為Card
設置一個 static 類型來捕獲錯誤可能很有用——沒有看到你的代碼我不知道這會有多大用處:
ColouredCard c = new ColouredCard(BLUE);
functionWhichOnlyTakesNumberedCards(c); // <-- helpful compile time error
像 tgdavies 的解決方案一樣,我會使用 Function 參數,但我不會修改 Card 子類。 (我並不是說我同意您的 inheritance 層次結構,但我沒有足夠的信息來真正質疑它。)
private static <C extends Card> boolean attributeMatches(
Card c1,
Card c2,
Class<C> cardType,
Function<C, ?> attribute) {
return cardType.isInstance(c1) && cardType.isInstance(c2)
&& Objects.equals(attribute.apply(c1), attribute.apply(c2));
}
public static boolean sameColor(Card c1, Card c2) {
return attributeMatches(c1, c2, ColoredCard, ColoredCard::getColor);
}
public static boolean sameNumber(Card c1, Card c2) {
return attributeMatches(c1, c2, NumberedCard, NumberedCard::getNumber);
}
public static boolean sameSpecialty(Card c1, Card c2) {
return attributeMatches(c1, c2, SpecialColoredCard, SpecialColoredCard::getSpecialty);
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.