設計模式(二十二)行為型:策略模式詳解

設計模式(二十二)行為型:策略模式詳解

策略模式(Strategy Pattern)是 GoF 23 種設計模式中最具實用性和廣泛影響力的行為型模式之一,其核心價值在于定義一系列算法或行為,并將每個算法封裝到獨立的類中,使得它們可以相互替換,且算法的變化獨立于使用它的客戶端。它通過將“算法”與“使用算法的上下文”解耦,實現了行為的動態配置與高度可擴展性。策略模式是構建可配置系統、實現多態行為、支持插件化架構、優化性能選擇、實現業務規則引擎、支持 A/B 測試等場景的基石,是將“算法即服務”理念落地的關鍵設計范式。

一、詳細介紹

策略模式解決的是“一個類有多種實現同一功能的算法,且這些算法需要在運行時根據條件動態選擇,或需要獨立于客戶端進行擴展和維護”的問題。在傳統設計中,通常使用條件語句(如 if-elseswitch-case)根據配置或參數選擇不同的算法分支。這導致:

  • 代碼臃腫:所有算法邏輯集中在單一方法或類中。
  • 難以擴展:新增算法需要修改現有代碼,違反開閉原則。
  • 難以復用:算法邏輯無法獨立復用。
  • 緊耦合:上下文類與具體算法實現緊密耦合。

策略模式的核心思想是:將每個算法封裝成一個獨立的類(策略類),這些類實現一個共同的策略接口。上下文類(Context)持有對策略接口的引用,通過多態調用算法,而無需知道具體實現。算法的切換通過注入不同的策略對象實現

該模式包含以下核心角色:

  • Context(上下文):定義客戶端使用的接口,包含一個對 Strategy 接口的引用。它將算法相關的請求委托給策略對象執行,而不關心具體實現。
  • Strategy(策略接口):定義所有具體策略類共有的操作接口(如 execute()calculate())。它聲明了算法的抽象行為。
  • ConcreteStrategyA, ConcreteStrategyB, …(具體策略類):實現 Strategy 接口,封裝具體的算法或行為實現。每個具體策略提供一種算法的完整實現。

策略模式的關鍵優勢:

  • 符合開閉原則:新增算法只需添加新的具體策略類,無需修改上下文或客戶端代碼。
  • 符合單一職責原則:每個策略類只負責一種算法的實現。
  • 算法可獨立復用:策略類可被多個上下文或系統復用。
  • 支持運行時切換:上下文可在運行時動態更換策略對象。
  • 消除條件語句:將 switch 邏輯轉化為對象組合。
  • 易于單元測試:每個策略可獨立測試。

與“狀態模式”相比,策略模式關注算法的替換,狀態模式關注狀態驅動的行為變化;策略通常由客戶端或配置決定,狀態轉換由內部邏輯驅動。與“命令模式”相比,命令封裝請求,策略封裝算法。與“模板方法模式”相比,模板方法在編譯時通過繼承固定算法骨架,策略在運行時通過組合動態選擇算法。

策略模式適用于:

  • 多種算法實現同一功能(如排序、壓縮、加密、支付方式、運費計算)。
  • 需要運行時動態選擇算法。
  • 需要避免龐大的條件分支。
  • 需要獨立測試或復用算法。
  • 實現業務規則引擎或配置化行為。

二、策略模式的UML表示

以下是策略模式的標準 UML 類圖:

uses
implements
implements
implements
Context
-strategy: Strategy
+setStrategy(strategy: Strategy)
+executeStrategy(data: Object)
?interface?
Strategy
+execute(data: Object)
ConcreteStrategyA
+execute(data: Object)
ConcreteStrategyB
+execute(data: Object)
ConcreteStrategyC
+execute(data: Object)

圖解說明

  • Context 持有對 Strategy 接口的引用。
  • Context 通過 setStrategy() 接受不同的策略實現。
  • ContextexecuteStrategy() 方法將調用委托給當前 Strategyexecute()
  • ConcreteStrategy 實現 execute(),提供具體算法。
  • 客戶端通過向 Context 注入不同的 ConcreteStrategy 來改變其行為。

三、一個簡單的Java程序實例及其UML圖

以下是一個電商系統中運費計算的示例,支持多種運費計算策略(標準、加急、免費)。

Java 程序實例
// 策略接口:運費計算器
interface ShippingCostStrategy {double calculate(double weight, double distance);
}// 具體策略:標準運費
class StandardShippingStrategy implements ShippingCostStrategy {private static final double RATE_PER_KG = 2.5;private static final double RATE_PER_KM = 0.1;@Overridepublic double calculate(double weight, double distance) {double cost = (weight * RATE_PER_KG) + (distance * RATE_PER_KM);System.out.println("📦 標準運費: " + weight + "kg × $" + RATE_PER_KG + "/kg + " + distance + "km × $" + RATE_PER_KM + "/km = $" + cost);return cost;}
}// 具體策略:加急運費
class ExpressShippingStrategy implements ShippingCostStrategy {private static final double BASE_FEE = 15.0;private static final double PREMIUM_RATE = 0.5; // per km@Overridepublic double calculate(double weight, double distance) {double cost = BASE_FEE + (distance * PREMIUM_RATE);// 重量影響較小,主要按距離和基礎費System.out.println("? 加急運費: 基礎費 $" + BASE_FEE + " + " + distance + "km × $" + PREMIUM_RATE + "/km = $" + cost);return cost;}
}// 具體策略:免費運費(促銷活動)
class FreeShippingStrategy implements ShippingCostStrategy {@Overridepublic double calculate(double weight, double distance) {System.out.println("🎁 免費運費: 訂單滿足促銷條件,運費為 $0.00");return 0.0;}
}// 上下文:購物車
class ShoppingCart {private double totalAmount;private double weight;private double distance;private ShippingCostStrategy shippingStrategy; // 持有策略引用public ShoppingCart(double totalAmount, double weight, double distance) {this.totalAmount = totalAmount;this.weight = weight;this.distance = distance;// 默認策略:標準運費this.shippingStrategy = new StandardShippingStrategy();System.out.println("🛒 購物車創建: 金額=$" + totalAmount + ", 重量=" + weight + "kg, 距離=" + distance + "km");}// 動態設置運費策略public void setShippingStrategy(ShippingCostStrategy strategy) {this.shippingStrategy = strategy;System.out.println("🔄 運費策略已切換");}// 計算總費用(商品金額 + 運費)public double calculateTotal() {double shippingCost = shippingStrategy.calculate(weight, distance);double total = totalAmount + shippingCost;System.out.println("💰 訂單總費用: $" + totalAmount + " + $" + shippingCost + " = $" + total);return total;}// 根據訂單金額自動應用免費運費(演示策略選擇邏輯)public void applyPromotion() {if (totalAmount >= 100.0) {System.out.println("🎉 訂單金額 ≥ $100,應用免費運費促銷!");setShippingStrategy(new FreeShippingStrategy());} else {System.out.println("🛒 訂單金額 < $100,不滿足免費運費條件。");}}
}// 客戶端使用示例
public class StrategyPatternDemo {public static void main(String[] args) {System.out.println("🛒 電商運費計算系統 - 策略模式示例\n");// 場景1: 普通訂單,使用標準運費System.out.println("--- 場景1: 普通訂單 ($80) ---");ShoppingCart cart1 = new ShoppingCart(80.0, 5.0, 200.0);cart1.calculateTotal(); // 使用默認標準策略System.out.println("\n--- 切換為加急運費 ---");cart1.setShippingStrategy(new ExpressShippingStrategy());cart1.calculateTotal();// 場景2: 大額訂單,應用促銷System.out.println("\n\n--- 場景2: 大額訂單 ($120) ---");ShoppingCart cart2 = new ShoppingCart(120.0, 3.0, 150.0);cart2.applyPromotion(); // 自動應用免費運費cart2.calculateTotal();System.out.println("\n--- 手動切換回標準運費(演示靈活性)---");cart2.setShippingStrategy(new StandardShippingStrategy());cart2.calculateTotal();}
}
實例對應的UML圖(簡化版)
uses
implements
implements
implements
ShoppingCart
-totalAmount: double
-weight: double
-distance: double
-shippingStrategy: ShippingCostStrategy
+setShippingStrategy(strategy: ShippingCostStrategy)
+calculateTotal()
+applyPromotion()
?interface?
ShippingCostStrategy
+calculate(weight: double, distance: double)
StandardShippingStrategy
+calculate(weight: double, distance: double)
ExpressShippingStrategy
+calculate(weight: double, distance: double)
FreeShippingStrategy
+calculate(weight: double, distance: double)

運行說明

  • ShoppingCart 是上下文,持有 ShippingCostStrategy 引用。
  • ShippingCostStrategy 定義運費計算接口。
  • 三種具體策略實現不同的計算邏輯。
  • ShoppingCart 通過 setShippingStrategy() 動態更換策略。
  • calculateTotal() 委托給當前策略的 calculate() 方法。
  • applyPromotion() 演示了根據業務規則自動選擇策略。

四、總結

特性說明
核心目的封裝可互換的算法,實現算法與使用的解耦
實現機制定義策略接口,上下文委托調用具體策略
優點符合開閉/單一職責原則、消除條件分支、支持運行時切換、算法可復用、易于測試
缺點增加類數量、客戶端需了解策略類型、簡單算法可能過度設計
適用場景多種算法選擇、配置化行為、插件化架構、業務規則引擎、A/B測試
不適用場景算法極少、行為固定、性能極度敏感(虛函數調用開銷)

策略模式使用建議

  • 策略類可設計為無狀態(推薦),便于共享和線程安全。
  • 可結合“工廠模式”或“依賴注入”創建和注入策略。
  • 在 Java 中,enum 可實現簡單策略(每個常量實現接口)。
  • 可結合“組合模式”實現復合策略。

架構師洞見:
策略模式是“關注點分離”與“依賴倒置”原則的典范。在現代架構中,其思想已演變為微服務架構(每個服務是業務策略的實現)、插件系統(如 IDE 插件、瀏覽器擴展)、A/B 測試框架(不同策略對應不同用戶組)、機器學習模型服務(不同模型作為預測策略)和 云原生配置管理(不同環境使用不同策略)。例如,Spring 框架的 PasswordEncoderLoadBalancer 都是策略模式的應用;Kubernetes 的調度器可選擇不同調度策略;在 AI 推理服務中,不同模型版本作為策略被動態切換。

未來趨勢是:策略模式將與Serverless 架構深度融合,每個函數即一個策略;在邊緣計算中,設備根據網絡狀況選擇數據處理策略;在量子計算中,不同量子算法作為策略被選擇;在元宇宙中,用戶交互邏輯可配置為不同策略。

掌握策略模式,是設計靈活、可配置、可演進系統的必備技能。作為架構師,應在設計任何需要“多選項”、“可配置行為”或“算法替換”的模塊時,優先考慮策略模式。它不僅是模式,更是系統適應性的靈魂——它讓系統擺脫了硬編碼的束縛,具備了在變化的環境中動態選擇最優路徑的能力,從而構建出能夠持續進化、自我優化的智能軟件生態系統。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/diannao/93862.shtml
繁體地址,請注明出處:http://hk.pswp.cn/diannao/93862.shtml
英文地址,請注明出處:http://en.pswp.cn/diannao/93862.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

AI+向量化

要理解 Java 如何結合 AI 與向量化&#xff0c;我們需要從向量化的核心概念、AI 中向量化的作用、Java 生態中的實現工具以及具體實踐案例四個維度展開。以下是詳細解析&#xff1a;一、核心概念&#xff1a;向量化與 AI 的關系向量化&#xff08;Vectorization&#xff09;是將…

Bootstap Vue 之b-form-radio-group 不顯示選中狀態問題

代碼類似&#xff1a;<b-form-radio-groupclass"mt-2"required:disabled"dfrmDisabled"v-model"childDikeForm.SafetyAppraisalRank":options"[一, 二, 三, 四]"name"rankradioopt"></b-form-radio-group>經過測…

Shell 腳本實戰:基于 for 循環的批量操作三例(賬戶創建、網絡檢測與密碼管理)

一、編寫腳本for1.sh,使用for循環創建20賬戶&#xff0c;賬戶名前綴由用戶從鍵盤輸入&#xff0c;賬戶初始密碼由用戶輸入&#xff0c;例如:test1、test2、test3、......、test10實現思路通過read命令獲取用戶輸入的賬戶前綴和初始密碼&#xff1b;加入非空校驗&#xff1a;若前…

PBR技術

一 、PBR的概述1.定義策略路由&#xff1a; PBR 是一種覆蓋路由器默認路由決策機制的技術。它允許管理員根據策略&#xff08;而不僅僅是目標地址&#xff09;來設置數據包的下一跳 IP 地址、出站接口、IP 優先級/DSCP 值等。路由策略&#xff1a;是指在路由器或三層設備上&…

STM32-ESP8266Wi-Fi模塊使用USART實現通信/創建AP和STA模式配置教程(寄存器版)

本章思維導圖&#xff1a;ESP8266WIFI模塊簡介ESP8266 是一款由樂鑫科技推出的低成本、高性能 Wi-Fi 模塊&#xff0c;廣泛應用于物聯網和嵌入式開發領域。WIFI的頻段5G和2.4G2.4G Wi-Fi與5G Wi-Fi最本質的區別即工作頻段&#xff08;無線電波的頻率&#xff09;不一樣&#xf…

算法26. 刪除有序數組中的重復項

給你一個 非嚴格遞增排列 的數組 nums &#xff0c;請你 原地 刪除重復出現的元素&#xff0c;使每個元素 只出現一次 &#xff0c;返回刪除后數組的新長度。元素的 相對順序 應該保持 一致 。然后返回 nums 中唯一元素的個數。 考慮 nums 的唯一元素的數量為 k &#xff0c;你…

ROS2中傳輸樣條曲線

在ROS2中傳輸樣條曲線需要解決兩個核心問題&#xff1a;**如何結構化表示曲線數據**和**如何高效傳輸**。以下是一套完整方案&#xff0c;結合自定義消息設計、序列化優化和QoS配置實現可靠傳輸&#xff1a;---### &#x1f4d0; 一、定義樣條曲線的自定義消息 樣條曲線通常由控…

Win11怎樣安裝DirectX 9

通過微軟官方下載安裝&#xff1a;確認系統兼容性并準備&#xff1a;確保顯卡驅動為最新版本&#xff0c;因為 DirectX 與顯卡驅動程序緊密相關。同時&#xff0c;可暫時關閉防病毒軟件和防火墻&#xff0c;防止其干擾安裝過程。下載安裝程序&#xff1a;訪問微軟官方網站下載 …

RAGFLOW~Enable RAPTOR

Enable RAPTOR 一種遞歸抽象方法&#xff0c;用于長上下文知識檢索和摘要&#xff0c;在廣泛語義理解和細微細節之間取得平衡。 RAPTOR&#xff08;遞歸抽象處理用于樹狀組織檢索&#xff09;是一種在2024年論文中引入的增強文檔預處理技術。它旨在解決多跳問答問題&#xff0c…

【機器人+相機通訊】宇樹科技相機通信

https://github.com/unitreerobotics/xr_teleoperate/blob/main/README_zh-CN.md 相機驅動與服務端 https://github.com/unitreerobotics/xr_teleoperate/blob/main/teleop/image_server/image_server.py 其中相機如果是realsense, 安裝好驅動后&#xff0c;可以使用命令查看…

機械學習中的一些優化算法(以邏輯回歸實現案例來講解)

一、混淆矩陣混淆矩陣是機器學習中評估分類模型性能的重要工具&#xff0c;尤其適用于二分類或多分類任務。它通過展示模型預測結果與實際標簽的匹配情況&#xff0c;幫助理解模型的錯誤類型&#xff08;如假陽性、假陰性等&#xff09;。以下通過二分類場景為例&#xff0c;結…

龍蜥受邀參加2025開放計算技術大會,解碼基礎模型驅動下的系統創新與生態共建

開放計算技術大會由全球最大的開放計算社區 OCP 發起&#xff0c;是開放計算領域生態覆蓋最廣且最具影響力的亞洲年度技術盛會。本屆大會由 OCP 與 OCTC&#xff08;中國電子工業標準化技術協會開放計算標準工作委員會&#xff09;兩大開放組織聯合主辦&#xff0c;將于 8 月 7…

第三階段—8天Python從入門到精通【itheima】-140節(pysqark實戰——基礎準備)

目錄 140節——pysqark實戰——基礎準備 1.學習目標 2.pysqark庫的安裝 3.pyspark的路徑安裝問題 一、為什么不需要指定路徑&#xff1f; 二、如何找到 pyspark 的具體安裝路徑&#xff1f; 三、驗證一下&#xff1a;直接定位 pyspark 的安裝路徑 四、總結&#xff1a;記…

數據庫中使用SQL作分組處理01(簡單分組)

1.簡單分組GroupBy什么就Select什么SELECT Name,Score From StudentScore GROUP BY Name,Score2.聚合函數(MAX SUM AVG COUNT)&#xff08;1&#xff09;計算1.表的全部字段都可以用聚合函數&#xff0c;但是篩選聚合函數的結果要用Having關鍵字2.聚合函數默認排除Null值IDName…

Linux基本服務——web服務解析

提示&#xff1a;文章寫完后&#xff0c;目錄可以自動生成&#xff0c;如何生成可參考右邊的幫助文檔 文章目錄 目錄 Web服務解析 虛擬Web主機 Web目錄訪問控制 Web服務解析 用途&#xff1a;基于 B/S 架構提供網頁的服務端程序 應用層協議&#xff1a;HTTP&#xff08;TCP 80…

深入理解緩存淘汰策略:LRU vs LFU 完全解析

深入理解緩存淘汰策略&#xff1a;LRU vs LFU 完全解析 文章目錄深入理解緩存淘汰策略&#xff1a;LRU vs LFU 完全解析前言一、基礎概念解析1.1 LRU&#xff08;Least Recently Used&#xff09;- 最近最少使用1.2 LFU&#xff08;Least Frequently Used&#xff09;- 最少使用…

【C語言】字符函數與字符串函數詳解

文章目錄一、字符分類函數二、字符轉換函數三、strlen函數&#xff1a;計算字符串長度功能說明使用示例模擬實現四、strcpy函數&#xff1a;字符串拷貝功能說明模擬實現五、strcat函數&#xff1a;字符串追加功能說明模擬實現六、strcmp函數&#xff1a;字符串比較比較規則模擬…

uvicorn 啟動重復加載 多次加載

目錄 uvicorn 啟動重復加載 多次加載 解決方法1&#xff1a; 解決方法2&#xff1a; uvicorn 啟動重復加載 多次加載 fastapi_aa 是當前類 解決方法1&#xff1a; import uvicornfrom fastapi import FastAPIapp FastAPI()if __name__ "__main__":if sys.gett…

Bard AI本地部署教程:在自己的服務器上運行谷歌AI

Bard AI本地部署教程:在自己的服務器上運行谷歌AI 關鍵詞:Bard AI、本地部署、服務器、谷歌AI、運行教程 摘要:本文旨在為大家詳細介紹如何在自己的服務器上實現Bard AI的本地部署。我們會從背景知識講起,逐步深入到核心概念、算法原理、操作步驟,還會提供項目實戰案例和實…

應急響應處置案例(上)

本文目錄 目錄 本文目錄 Web安全事件 概述 案例1 - webshell 背景 排查情況 天眼 服務器 案例2 - Struts2 排查情況 天眼 服務器 案例3 - Redis未授權 背景 排查情況 天眼 服務器 案例4 - EW內網穿透 背景 排查情況 天眼 服務器 案例5 - 一句話木馬 背…