簡體   English   中英

如何避免 instanceOf 和動態 getter 檢查?

[英]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 層次結構: NumberedCardSpecialColoredCard都擴展了抽象ColoredCard class。 如何避免冗余? 我是否應該讓所有這些實現一個新的CardWithKeyProperty interface並將這些方法重構為單個doBothHaveTheSameKeyProperty()方法? 但是我再次不確定,因為ColoredCard在 inheritance 層次結構中要高一級,所以它們都實現了相同的接口聽起來不正確。

就像評論中提到的那樣,inheritance 並不總是最好的解決方案。 使用 NumberedCard 和 ColoredCard 對這種情況進行建模並不是很有用。 因為彩色卡片總是有一個數字,而編號卡片總是有一個顏色,所以為什么要把這些概念分開。

我會創建兩個類。 一張為帶有顏色和編號的 NormalCard,另一張為 SpecialCard。 並且在接口卡中應該存在一個方法 compatibleTo()。

只是我的2c

  • 將吸氣劑放在您的基卡 class 上,但將它們的返回類型設為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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM