此代碼來自CardUtility我在應用程式中使用的類。
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檢查,并且由于繼承層次結構:NumberedCard并且SpecialColoredCard都擴展了抽象ColoredCard類。如何避免冗余?我應該讓所有這些實作一個新的CardWithKeyProperty interface方法并將這些方法重構為一個doBothHaveTheSameKeyProperty()方法嗎?但我又不確定,因為ColoredCard繼承層次結構更高一級,因此所有實作相同介面的方法聽起來都不正確。
uj5u.com熱心網友回復:
- 穿上你的基卡類的干將,但讓他們回傳型別
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);
并使用map在compareCards:
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在編譯時使用靜態型別來捕獲錯誤可能很有用- 沒有看到您的代碼,我不知道這會有多大用處:
ColouredCard c = new ColouredCard(BLUE);
functionWhichOnlyTakesNumberedCards(c); // <-- helpful compile time error
uj5u.com熱心網友回復:
就像評論中提到的那樣,繼承并不總是最好的解決方案。用 NumberedCard 和 ColoredCard 對這個場景進行建模,恕我直言不是很有用。因為有顏色的卡片總會有一個數字,而一張有編號的卡片總會有一種顏色,所以為什么要把這些概念分開。
我會創建兩個類。一張是帶有顏色和號碼的 NormalCard,另一張是 SpecialCard。并且在介面 Card 中應該存在一個方法 compatibleTo()。
只是我的 2c
uj5u.com熱心網友回復:
像 tgdavies 的解決方案一樣,我會使用 Function 引數,但我不會修改 Card 子類。(我并不是說我同意你的繼承層次,但我沒有足夠的資訊來真正質疑它。)
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);
}
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/364767.html
