118. Java 接口 – 接口功能增强实战默认方法、静态方法与Comparator链式排序策略
默认方法(default methods)使得可以为现有接口添加新功能,并且确保与旧版本接口兼容。通过使用默认方法,能够在不破坏旧版代码的情况下为接口添加新方法,甚至支持使用 lambda 表达式作为参数。这为库的扩展和版本兼容性提供了强劲的支持。
接下来,我们通过增强 Comparator 接口来展示如何使用默认方法和静态方法来实现更灵活的功能。
示例:扩展 Comparator 接口
假设我们有两个接口:Card 和 Deck。Card 接口定义了两种枚举类型 Suit 和 Rank,以及两个抽象方法 getSuit() 和 getRank()。
Card 接口
public interface Card extends Comparable<Card> {
public enum Suit {
DIAMONDS(1, "Diamonds"),
CLUBS(2, "Clubs"),
HEARTS(3, "Hearts"),
SPADES(4, "Spades");
private final int value;
private final String text;
Suit(int value, String text) {
this.value = value;
this.text = text;
}
public int value() { return value; }
public String text() { return text; }
}
public enum Rank {
DEUCE(2, "Two"),
THREE(3, "Three"),
FOUR(4, "Four"),
FIVE(5, "Five"),
SIX(6, "Six"),
SEVEN(7, "Seven"),
EIGHT(8, "Eight"),
NINE(9, "Nine"),
TEN(10, "Ten"),
JACK(11, "Jack"),
QUEEN(12, "Queen"),
KING(13, "King"),
ACE(14, "Ace");
private final int value;
private final String text;
Rank(int value, String text) {
this.value = value;
this.text = text;
}
public int value() { return value; }
public String text() { return text; }
}
public Suit getSuit();
public Rank getRank();
}
Deck 接口
Deck 接口定义了对卡片组的操作,包括排序、添加卡片、洗牌等方法。
public interface Deck {
List<Card> getCards();
Deck deckFactory();
int size();
void addCard(Card card);
void addCards(List<Card> cards);
void addDeck(Deck deck);
void shuffle();
void sort();
void sort(Comparator<Card> c);
String deckToString();
Map<Integer, Deck> deal(int players, int numberOfCards)
throws IllegalArgumentException;
}
PlayingCard 类
PlayingCard 类实现了 Card 接口,并提供了实现细节。
public class PlayingCard implements Card {
private Rank rank;
private Suit suit;
// constructor
@Override
public Suit getSuit() {
return this.suit;
}
@Override
public Rank getRank() {
return this.rank;
}
@Override
public int compareTo(Card o) {
return this.hashCode() - o.hashCode();
}
@Override
public int hashCode() {
return ((suit.value() - 1) * 13) + rank.value();
}
}
StandardDeck 类
StandardDeck 类实现了 Deck 接口,并提供了排序功能。使用 Collections.sort() 方法对 Deck 进行排序。
public class StandardDeck implements Deck {
private List<Card> entireDeck;
// constructor, accessors
@Override
public void sort() {
Collections.sort(entireDeck);
}
@Override
public void sort(Comparator<Card> c) {
Collections.sort(entireDeck, c);
}
}
在此例中,compareTo() 方法在 PlayingCard 类中实现,用于按花色和等级对卡片进行排序。StandardDeck.sort() 方法默认按照 compareTo() 的规则对卡片进行排序。
按等级和花色排序
如果需要按等级排序,然后按花色排序,可以使用 Comparator 接口实现自定义排序规则:
public class SortByRankThenSuit implements Comparator<Card> {
@Override
public int compare(Card firstCard, Card secondCard) {
int compVal = firstCard.getRank().value() - secondCard.getRank().value();
if (compVal != 0)
return compVal;
else
return firstCard.getSuit().value() - secondCard.getSuit().value();
}
}
使用 Comparator 对 Deck 进行排序:
StandardDeck myDeck = new StandardDeck();
myDeck.shuffle();
myDeck.sort(new SortByRankThenSuit());
使用 Lambda 表达式简化排序
使用 lambda 表达式,可以简化排序逻辑,不必显式定义 Comparator 类。例如,按等级排序:
StandardDeck myDeck = new StandardDeck();
myDeck.shuffle();
myDeck.sort((firstCard, secondCard) ->
firstCard.getRank().value() - secondCard.getRank().value()
);
增强 Comparator 接口:静态方法
Comparator 接口已经通过静态方法增强,允许您使用更简洁的方式定义排序规则。例如,按 Card 的 Rank 排序:
myDeck.sort(Comparator.comparing(Card::getRank));
这种方式允许您使用方法引用来简化代码。静态方法 Comparator.comparing() 提供了基于属性的比较功能。
链式排序:thenComparing()
Comparator 接口的默认方法 thenComparing() 可以让您将多个比较标准组合起来。例如,先按等级排序,再按花色排序:
myDeck.sort(
Comparator
.comparing(Card::getRank)
.thenComparing(Card::getSuit)
);
反向排序:reversed()
如果需要对排序结果进行反转(例如按等级降序排序),Comparator 接口提供了 reversed() 方法:
myDeck.sort(
Comparator.comparing(Card::getRank)
.reversed()
.thenComparing(Card::getSuit)
);
总结
- 默认方法:通过向接口添加默认方法,您可以扩展现有接口的功能,而不会破坏旧版代码。
-
静态方法:
Comparator接口的静态方法使得排序更加简洁,并允许您使用 lambda 表达式或方法引用来创建比较器。 -
链式排序:
thenComparing()方法使您能够组合多个比较条件,增强了排序的灵活性。 -
反向排序:通过
reversed()方法,您可以轻松地对排序结果进行反转。
通过这些增强功能,可以创建更简洁、更灵活的排序逻辑,使得库的使用更加方便和易于理解。这些功能极大地提升了 Java 接口的表现力和可用性。