C/C++ 有函數指針,可將「調用特定函數的能力」作為參數傳遞。Java 無函數指針,但可用對象引用實現同樣功能:定義一個只有一個核心方法的類,其實例即為函數對象,等價於函數指針。這正是策略模式的 Java 實現方式。
class StringLengthComparator {
public int compare(String s1, String s2) {
return s1.length() - s2.length();
}
}
此類無狀態,所有實例功能等價 → 適合單例模式。
public class StringLengthComparator {
private StringLengthComparator() {} // 私有構造
public static final StringLengthComparator INSTANCE = new StringLengthComparator();
public int compare(String s1, String s2) {
return s1.length() - s2.length();
}
}
// 策略接口 (java.util.Comparator)
public interface Comparator<T> {
int compare(T t1, T t2);
}
// 實現接口
public class StringLengthComparator implements Comparator<String> {
// ... 同前
}
關鍵點:接口泛型化,使策略不限於 String,復用性最大化。
String[] words = {"apple", "banana", "pear", "orange"};
// Java 7 匿名類
Arrays.sort(words, new Comparator<String>() {
@Override
public int compare(String s1, String s2) {
return s1.length() - s2.length();
}
});
// Java 8+ Lambda (函數式接口自動適配)
Arrays.sort(words, (s1, s2) -> s1.length() - s2.length());
// 或方法引用
Arrays.sort(words, Comparator.comparingInt(String::length));
每次調用 Arrays.sort 都會創建新匿名類實例。若在熱點循環中,應提取為 private static final 常量復用。
匿名類無法實現多個接口,需用具名靜態內部類:
public class Host {
// 策略接口
public interface Comparator<T> extends Serializable {
int compare(T t1, T t2);
}
// 具體策略:私有靜態成員類,實現 Comparator + Serializable
private static class StrLenCmp implements Comparator<String>, Serializable {
private static final long serialVersionUID = -5797980299250787300L;
@Override
public int compare(String s1, String s2) {
return s1.length() - s2.length();
}
}
// 公開導出:類型為接口,隱藏具體實現類
public static final Comparator<String> STRING_LENGTH_COMPARATOR = new StrLenCmp();
public static void main(String[] args) {
System.out.println(STRING_LENGTH_COMPARATOR.compare("aaaaaa", "aaaaa")); // 輸出 1
}
}
public final class String {
// ...
public static final Comparator<String> CASE_INSENSITIVE_ORDER
= new CaseInsensitiveComparator();
private static class CaseInsensitiveComparator
implements Comparator<String>, Serializable {
// 忽略大小寫比較邏輯
}
}
標準庫廣泛使用此模式:Collections.reverseOrder()、Comparator.naturalOrder() 等均返回單例策略對象。
@FunctionalInterface。private static class + static final 單例導出;有狀態 → 普通類或 Builder 構建。Serializable,通過宿主類 public static final 接口類型字段導出。private,符合依賴倒置原則。| 場景 | 推薦寫法 | 關鍵字 |
|---|---|---|
| 臨時、一次性策略 | Lambda / 匿名類 | ->, new Interface() {} |
| 無狀態、全局復用 | 私有靜態類 + static final 常量 | private static class, INSTANCE |
| 需序列化/多接口 | 具名靜態成員類 implements 多接口 | implements A, B |
| 有狀態策略 | 普通類構造函數注入狀態 | new Strategy(config) |