策略模式是「行為型模式」中最實用、最常被面試考察的一種。本文從**定義、角色結構、代碼實戰、JDK 源碼剖析 (Collections.sort + Comparator)、優缺點與避坑指南**五個維度,系統講解策略模式,助你在實際專案中靈活應用「算法族封裝與熱插拔」。
// 1. 抽象策略
public interface PayStrategy {
void pay(double amount);
}
// 2. 具體策略
public class AlipayStrategy implements PayStrategy {
@Override public void pay(double amount) { System.out.println("支付寶支付: " + amount); }
}
public class WechatPayStrategy implements PayStrategy {
@Override public void pay(double amount) { System.out.println("微信支付: " + amount); }
}
public class UnionPayStrategy implements PayStrategy {
@Override public void pay(double amount) { System.out.println("銀聯支付: " + amount); }
}
// 3. 環境角色
public class PaymentContext {
private PayStrategy strategy;
public PaymentContext(PayStrategy strategy) { this.strategy = strategy; }
public void setStrategy(PayStrategy strategy) { this.strategy = strategy; }
public void executePayment(double amount) { strategy.pay(amount); }
}
// 4. 客戶端使用
PaymentContext ctx = new PaymentContext(new AlipayStrategy());
ctx.executePayment(100); // 支付寶支付: 100.0
ctx.setStrategy(new WechatPayStrategy());
ctx.executePayment(200); // 微信支付: 200.0
Collections.sort(List<T>, Comparator<? super T>) 是教科書級策略模式應用:
Collections.sort() 方法(內部委派給 List.sort() → Arrays.sort() → TimSort)。Comparator<T> 介面,單一方法 compare(T o1, T o2)。String.CASE_INSENSITIVE_ORDER、Collections.reverseOrder()、Lambda 表達式 (a,b) -> a - b。
Collections.sort(list, comparator)
→ list.sort(comparator) // List 介面默認方法
→ Arrays.sort(array, comparator) // 轉陣列排序
→ TimSort.sort(array, comparator) // 核心排序邏輯
→ comparator.compare(o1, o2) // 關鍵:策略方法被調用
// TimSort.java 片段
private static void mergeSort(Object[] src, Object[] dest, int low, int high, int off, Comparator super T> c) {
// ...
if (c.compare(src[mid-1], src[mid]) <= 0) { // 策略調用:判斷是否已有序
System.arraycopy(src, low, dest, destLow, length);
return;
}
// 合併階段
for (int i = destLow, p = low, q = mid; i < destHigh; i++) {
if (q >= high || (p < mid && c.compare(src[p], src[q]) <= 0)) // 策略調用:歸併比較
dest[i] = src[p++];
else
dest[i] = src[q++];
}
}
| 優點 | 缺點/注意 |
|---|---|
| 算法與客戶端解耦,符合開閉原則 | 策略類數量膨脹,需配合工廠/註冊表管理 |
| 避免大量 if-else/switch 分支 | 客戶端必須了解所有策略才能選擇 |
| 支援運行時熱切換算法 | 策略介面設計不當導致參數傳遞困擾 |
| 算法可獨立測試、複用 | 若策略需共享狀態,需額外設計 Context 狀態傳遞 |
@Component
public class PayStrategyRegistry {
private final Map strategies = new ConcurrentHashMap<>();
@PostConstruct
public void init(List all) {
all.forEach(s -> strategies.put(s.getClass().getSimpleName().replace("Strategy", "").toLowerCase(), s));
}
public PayStrategy get(String name) {
PayStrategy s = strategies.get(name.toLowerCase());
if (s == null) throw new IllegalArgumentException("未知支付策略: " + name);
return s;
}
}
// 使用
@Autowired PayStrategyRegistry registry;
PaymentContext ctx = new PaymentContext(registry.get("alipay"));
ctx.executePayment(100);
Comparator 是最經典、最頻繁使用的策略模式實例。靈活運用策略模式,能讓業務邏輯清晰、擴展優雅、測試簡單。