策略模式定義算法族,封裝每個算法,使其可互換。適用於「同一行為、多種實現」場景。本文對比「if-else 硬編碼」與「策略模式」實現會員等級折扣,展示開閉原則威力。
public class NoStrategy {
private static final int NORMAL = 1, SILVER = 2, GOLD = 3;
public double getPrice(double price, int level) {
if (level == NORMAL) return price;
else if (level == SILVER) return price * 0.9;
else if (level == GOLD) return price * 0.7;
else return 0;
}
}
// 新增鑽石會員?必須修改源碼、新增常量、新增分支 → 違反開閉原則
public interface PriceStrategy {
double calculate(double price);
}
public class NormalStrategy implements PriceStrategy {
public double calculate(double price) { return price; }
}
public class SilverStrategy implements PriceStrategy {
public double calculate(double price) { return price * 0.9; }
}
public class GoldStrategy implements PriceStrategy {
public double calculate(double price) { return price * 0.7; }
}
public class PriceContext {
private PriceStrategy strategy;
public PriceContext(PriceStrategy strategy) { this.strategy = strategy; }
public double getPrice(double price) { return strategy.calculate(price); }
}
public class Test {
public static void main(String[] args) {
System.out.println("普通會員: " + new PriceContext(new NormalStrategy()).getPrice(100));
System.out.println("銀卡會員: " + new PriceContext(new SilverStrategy()).getPrice(100));
System.out.println("金卡會員: " + new PriceContext(new GoldStrategy()).getPrice(100));
}
}
優點 缺點 結構清晰,算法邏輯與業務邏輯分離 策略類數量隨業務增長(可用枚舉/工廠緩解) 符合開閉原則,新增策略零修改現有代碼 客戶端需知曉所有策略類(可引入工廠模式封裝創建) 避免巨大條件分支,降低圈複雜度 策略間無法共享狀態(需通過 Context 傳遞) 數據安全:策略細節封裝,外部不可篡改 — 實戰應用場景
- **支付渠道**:微信/支付寶/銀聯/貝寶,各自實現 `PayStrategy`。
- **排序算法**:快排/歸併/堆排/計數排序,`SortStrategy` 可運行時切換。
- **壓縮算法**:ZIP/GZIP/BZIP2/LZ4,`CompressionStrategy`。
- **路由/負載均衡**:輪詢/隨機/一致性哈希/最少連接,`LoadBalanceStrategy`。
- **Spring 源碼大量應用**:`ResourceLoader`、`ConversionService`、`TransactionManager` 選型等。
進階:策略工廠簡化客戶端
public class StrategyFactory { private static final Map<String, PriceStrategy> MAP = new HashMap<>(); static { MAP.put("NORMAL", new NormalStrategy()); MAP.put("SILVER", new SilverStrategy()); MAP.put("GOLD", new GoldStrategy()); MAP.put("DIAMOND", new DiamondStrategy()); } public static PriceStrategy get(String level) { return MAP.getOrDefault(level.toUpperCase(), new NormalStrategy()); } } // 使用 double price = new PriceContext(StrategyFactory.get("GOLD")).getPrice(100);