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

Java 設計模式精講:策略模式—— 封裝算法族,實現運行時動態切換

     編輯:Java 綜合教學

前言:如果不使用策略模式會怎樣?

假設電商系統需根據會員等級計算折扣:普通會員無折扣、銀卡 9 折、金卡 8 折、鉑金 7 折。若用 if-else 或 switch 硬編碼:

public double calcPrice(User user, double price) {
    if (user.getLevel() == Level.NORMAL) return price;
    else if (user.getLevel() == Level.SILVER) return price * 0.9;
    else if (user.getLevel() == Level.GOLD) return price * 0.8;
    else if (user.getLevel() == Level.PLATINUM) return price * 0.7;
    return price;
}

痛點:新增等級需修改核心邏輯(違反開閉原則);測試需覆蓋所有分支;折扣算法無法復用;業務邏輯與算法耦合。

策略模式通過將算法封裝為獨立類、統一接口、運行時注入,完美解決上述問題。

一、模式定義與核心角色

策略模式定義了一系列算法,將每一個算法封裝起來,並使它們可以相互替換。策略模式讓算法的變化獨立於使用算法的客戶端。

角色職責示例類
Strategy(抽象策略)定義算法公共接口MemberStrategy
ConcreteStrategy(具體策略)實現具體算法Primary/Intermediate/AdvancedMemberStrategy
Context(環境角色)持有策略引用,委派算法執行Price(價格計算上下文)

二、標準實現代碼

2.1 抽象策略接口

public interface MemberStrategy {
    /**
     * 計算折扣價
     * @param booksPrice 原價
     * @return 折扣後價格
     */
    double calcPrice(double booksPrice);
}

2.2 具體策略實現

// 普通會員:無折扣
public class PrimaryMemberStrategy implements MemberStrategy {
    @Override
    public double calcPrice(double booksPrice) {
        System.out.println("普通會員:無折扣");
        return booksPrice;
    }
}

// 銀卡會員:9 折
public class IntermediateMemberStrategy implements MemberStrategy {
    @Override
    public double calcPrice(double booksPrice) {
        System.out.println("銀卡會員:9 折優惠");
        return booksPrice * 0.9;
    }
}

// 金卡會員:8 折
public class AdvancedMemberStrategy implements MemberStrategy {
    @Override
    public double calcPrice(double booksPrice) {
        System.out.println("金卡會員:8 折優惠");
        return booksPrice * 0.8;
    }
}

2.3 環境角色(上下文)

public class Price {
    private final MemberStrategy strategy; // 策略引用

    public Price(MemberStrategy strategy) {
        this.strategy = strategy;
    }

    /** 設置策略(支持運行時動態切換) */
    public void setStrategy(MemberStrategy strategy) {
        this.strategy = strategy;
    }

    /** 委派策略執行計算 */
    public double quote(double booksPrice) {
        return strategy.calcPrice(booksPrice);
    }
}

2.4 客戶端調用

public class Client {
    public static void main(String[] args) {
        // 1. 創建具體策略
        MemberStrategy strategy = new AdvancedMemberStrategy(); // 金卡策略
        // 2. 創建環境並注入策略
        Price price = new Price(strategy);
        // 3. 執行計算
        double quote = price.quote(300);
        System.out.println("圖書最終價格:" + quote); // 輸出:240.0

        // 運行時動態切換策略
        price.setStrategy(new PrimaryMemberStrategy());
        System.out.println("切換為普通會員價格:" + price.quote(300)); // 輸出:300.0
    }
}

三、進階應用:Spring 整合策略模式實現「零 if-else」

3.1 策略註冊為 Spring Bean

@Component("primaryStrategy")
public class PrimaryMemberStrategy implements MemberStrategy { ... }

@Component("intermediateStrategy")
public class IntermediateMemberStrategy implements MemberStrategy { ... }

@Component("advancedStrategy")
public class AdvancedMemberStrategy implements MemberStrategy { ... }

3.2 策略工廠:根據業務鍵自動獲取 Bean

3.3 業務服務中零硬編碼調用

效果:新增會員等級只需新增 Strategy 實現類並註冊 Bean,核心業務代碼零修改,完美遵循開閉原則。

四、策略模式 vs 狀態模式 vs 模板方法模式

維度策略模式狀態模式模板方法模式
核心目的封裝可互換算法族對象狀態改變行為定義算法骨架,延遲步驟
切換時機客戶端顯式/隱式選擇內部狀態自動流轉子類繼承時確定
結構關係組合(Context 持有 Strategy)組合(Context 持有 State)繼承(子類實現抽象方法)
典型場景支付方式、排序算法、壓縮策略、折扣計算訂單狀態機、工作流引擎、遊戲角色狀態數據導出、請求處理流程、測試模板

五、優缺點總結

優點缺點
  • 消除大量條件分支,代碼清晰
  • 算法獨立封裝,易於單元測試、復用
  • 支持運行時動態切換算法
  • 符合開閉原則,新增策略不修改現有代碼
  • 隱藏複雜算法實現細節
  • 策略類數量增加(可用工廠/註解管理)
  • 客戶端需了解所有策略以便選擇
  • 策略接口變更影響所有實現
  • 不適用於算法極少且固定場景

六、JDK 與框架源碼中的經典應用

  • java.util.Comparator:排序策略,Collections.sort(list, comparator)
  • Spring Resource 接口:ClassPathResource、FileSystemResource、UrlResource 等加載策略
  • Spring TransactionManager:DataSourceTransactionManager、JtaTransactionManager 等事務策略
  • Spring Security AuthenticationManager:多種認證策略鏈

七、總結

策略模式是「組合優於繼承」原則的典型實踐。它將易變的算法從穩定的業務邏輯中剝離,通過接口抽象 + 組合委派實現算法的即插即用。結合 Spring 依賴注入與工廠模式,可構建極具擴展性的「零 if-else」業務架構。掌握策略模式,是從「寫代碼」進階到「設計系統」的關鍵一步。

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