首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> Java 程式設計 >> Java 相關知識

Java 策略模式深度解析:從定義到 Collections.sort 實戰源碼剖析

     編輯:Java 相關知識

策略模式是「行為型模式」中最實用、最常被面試考察的一種。本文從**定義、角色結構、代碼實戰、JDK 源碼剖析 (Collections.sort + Comparator)、優缺點與避坑指南**五個維度,系統講解策略模式,助你在實際專案中靈活應用「算法族封裝與熱插拔」。

一、模式定義與角色

  • 意圖: 定義一組算法,封裝每個算法,使它們**可以互相替換**。策略模式讓算法的變化獨立於使用算法的客戶端。
  • 三大角色:
  1. Context (環境角色): 持有 Strategy 引用,委派具體算法執行。
  2. Strategy (抽象策略): 介面或抽象類,定義算法契約。
  3. ConcreteStrategy (具體策略): 實作具體算法邏輯。

二、標準代碼實戰


// 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

三、JDK 源碼剖析:Collections.sort + Comparator = 策略模式

Collections.sort(List<T>, Comparator<? super T>) 是教科書級策略模式應用:

  • Context: Collections.sort() 方法(內部委派給 List.sort() → Arrays.sort() → TimSort)。
  • Strategy: Comparator<T> 介面,單一方法 compare(T o1, T o2)。
  • ConcreteStrategy: 各種比較器實現,如 String.CASE_INSENSITIVE_ORDER、Collections.reverseOrder()、Lambda 表達式 (a,b) -> a - b。

源碼追蹤鏈路 (JDK 17)


Collections.sort(list, comparator)
    → list.sort(comparator)  // List 介面默認方法
        → Arrays.sort(array, comparator)  // 轉陣列排序
            → TimSort.sort(array, comparator)  // 核心排序邏輯
                → comparator.compare(o1, o2)  // 關鍵:策略方法被調用

TimSort 中關鍵調用點


// TimSort.java 片段
private static  void mergeSort(Object[] src, Object[] dest, int low, int high, int off, Comparator 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 狀態傳遞

五、進階應用:策略註冊表 + 工廠 (Spring 風格)


@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);

六、總結

  • 策略模式 = **算法族封裝 + 委派調用 + 運行時可替換**。
  • JDK Comparator 是最經典、最頻繁使用的策略模式實例。
  • 實戰中結合 **工廠/註冊表 + 依賴注入** 管理策略實例,實現「配置化選擇算法」。
  • 避免將「狀態」放入 Strategy,保持 Strategy **無狀態、可共享、線程安全**。

靈活運用策略模式,能讓業務邏輯清晰、擴展優雅、測試簡單。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved