【軟件設計模式】策略模式

1.概念

????????策略(Strategy)模式定義了一系列算法,并將每個算法封裝起來,使它們可以相互替換,且算法的變化不會影響使用算法的客戶。策略模式屬于行為型設計模式,它通過對算法進行封裝,把使用算法的責任和算法的實現分割開來,并委派給不同的對象對這些算法進行管理。

?策略模式可以簡單理解為:“一件事有多種做法,你可以隨時換著來,不用改其他地方”

打個生活比方:
比如你要去上班(這是 “目標”),可以有多種方式(這些方式就是 “策略”):

  • 晴天騎共享單車
  • 下雨打出租車
  • 趕時間就坐地鐵

????????這些方式都是去上班的辦法,互不影響。你可以根據天氣、時間隨時換,而 “上班” 這個目標本身不用變,換方式時也不用改其他安排。

????????核心就是:把做一件事的不同方法單獨拎出來,想用哪個就用哪個,切換起來很方便,還不影響其他部分

2.策略模式結構

策略模式包含 3 個核心角色:

  1. 策略接口(Strategy):定義所有支持的算法的公共接口(或抽象類),聲明算法的核心方法。
  2. 具體策略(ConcreteStrategy):實現策略接口,包含具體的算法邏輯(如不同的排序算法、支付方式等)。
  3. 上下文(Context):持有一個策略接口的引用,負責調用策略的算法。客戶端通過上下文間接使用策略,且上下文可動態切換策略(通過 setter 方法)。

3.優點

  • 靈活性高:算法可動態切換,客戶端無需修改代碼即可更換策略。
  • 符合開閉原則:新增算法只需新增具體策略類,無需修改上下文或其他策略。
  • 避免多重條件判斷:用多態代替if-elseswitch語句,代碼更清晰。
  • 算法復用:策略類可在不同場景中復用。

4.適用場景

  • 當一個問題有多種解決方案(算法),且需要動態選擇其中一種時(如支付系統的多種支付方式、排序算法的選擇)。
  • 當代碼中存在大量與算法相關的if-else判斷,且這些算法可能頻繁變化時。
  • 當需要隱藏算法的具體實現細節,只暴露其接口時。

5.策略模式示例

說明:設計一個?“折扣計算” 模塊,支持 3 種折扣策略:

  • 新用戶折扣(滿 100 減 20)
  • 會員折扣(9 折)
  • 促銷折扣(滿 200 減 50)
// 1. 策略接口:定義折扣計算方法
public interface DiscountStrategy {// 計算折扣后金額:參數為原價,返回折后價double calculate(double originalPrice);
}// 2. 具體策略:新用戶折扣
public class NewUserDiscount implements DiscountStrategy {@Overridepublic double calculate(double originalPrice) {// 滿100減20return originalPrice >= 100 ? originalPrice - 20 : originalPrice;}
}// 具體策略:會員折扣(9折)
public class MemberDiscount implements DiscountStrategy {@Overridepublic double calculate(double originalPrice) {return originalPrice * 0.9;}
}// 具體策略:促銷折扣(滿200減50)
public class PromotionDiscount implements DiscountStrategy {@Overridepublic double calculate(double originalPrice) {return originalPrice >= 200 ? originalPrice - 50 : originalPrice;}
}// 3. 上下文:折扣計算器(使用策略的類)
public class DiscountContext {// 持有策略接口的引用private DiscountStrategy strategy;// 構造方法:初始化時指定策略public DiscountContext(DiscountStrategy strategy) {this.strategy = strategy;}// 動態切換策略public void setStrategy(DiscountStrategy strategy) {this.strategy = strategy;}// 調用策略計算折扣public double getFinalPrice(double originalPrice) {return strategy.calculate(originalPrice);}
}// 1. 策略接口:定義折扣計算方法
public interface DiscountStrategy {// 計算折扣后金額:參數為原價,返回折后價double calculate(double originalPrice);
}// 2. 具體策略:新用戶折扣
public class NewUserDiscount implements DiscountStrategy {@Overridepublic double calculate(double originalPrice) {// 滿100減20return originalPrice >= 100 ? originalPrice - 20 : originalPrice;}
}// 具體策略:會員折扣(9折)
public class MemberDiscount implements DiscountStrategy {@Overridepublic double calculate(double originalPrice) {return originalPrice * 0.9;}
}// 具體策略:促銷折扣(滿200減50)
public class PromotionDiscount implements DiscountStrategy {@Overridepublic double calculate(double originalPrice) {return originalPrice >= 200 ? originalPrice - 50 : originalPrice;}
}// 3. 上下文:折扣計算器(使用策略的類)
public class DiscountContext {// 持有策略接口的引用private DiscountStrategy strategy;// 構造方法:初始化時指定策略public DiscountContext(DiscountStrategy strategy) {this.strategy = strategy;}// 動態切換策略public void setStrategy(DiscountStrategy strategy) {this.strategy = strategy;}// 調用策略計算折扣public double getFinalPrice(double originalPrice) {return strategy.calculate(originalPrice);}
}

客戶端:

public DiscountStrategy strategy(String role) {switch (role) {case "new":return new NewUserDiscount();case "member":return new MemberDiscount();case "promotion":return new PromotionDiscount();default:throw new IllegalArgumentException("未知用戶類型");}}

? ? ? ? 可見雖然我們采用策略模式進行算法封裝,但是在邏輯分配時還是使用到了if-else式硬編碼格式,到后續我們想要新增新的策略也需要修改客戶端的代碼!

6.策略模式優化

????????策略模式的核心是封裝算法變化,讓客戶端可以靈活切換不同實現,避免冗余的條件判斷。它與工廠方法模式都通過抽象接口實現解耦,但策略模式聚焦 “行為 / 算法的使用”,工廠方法聚焦 “對象的創建”。實際開發中,兩者常結合使用:用工廠方法創建策略對象,用策略模式使用這些對象,既簡化了對象創建,又實現了算法的靈活切換。

說明:使用工廠方法+Map集合+策略模式優化

????????使用工廠方法可將對象的創建解耦,使用Map集合可消除if-else,使用策略模式可將算法的使用解耦。

/*** 角色處理器接口* 策略模式的核心接口,定義不同角色的處理行為*/
@FunctionalInterface
public interface RoleHandler {/*** 處理用戶角色相關業務邏輯* @param userDTO 用戶數據傳輸對象*/void handle(UserDTO userDTO);
}/*** 管理員角色處理器* 處理管理員角色相關的業務邏輯*/
@Component
public class ManagerRoleHandler implements RoleHandler {@Resourceprivate ManagerMapper managerMapper;@Overridepublic void handle(UserDTO userDTO) {managerMapper.insertManager(userDTO);}
}/*** 學生角色處理器* 處理學生角色相關的業務邏輯*/
@Component
public class StudentRoleHandler implements RoleHandler {@Resourceprivate StudentMapper studentMapper;@Overridepublic void handle(UserDTO userDTO) {studentMapper.insertStudent(userDTO);}
}/*** 教師角色處理器* 處理教師角色相關的業務邏輯*/
@Component
public class TeacherRoleHandler implements RoleHandler {@Resourceprivate TeacherMapper teacherMapper;@Overridepublic void handle(UserDTO userDTO) {teacherMapper.insertTeacher(userDTO);}
}/*** 角色處理器工廠* 用于獲取不同角色的處理器實例*/
@Component
public class RoleHandlerFactory {private final Map<String, RoleHandler> roleHandlerMap = new HashMap<>();public RoleHandlerFactory(StudentRoleHandler studentRoleHandler, TeacherRoleHandler teacherRoleHandler, ManagerRoleHandler managerRoleHandler) {roleHandlerMap.put(RedisConstant.STUDENT, studentRoleHandler);roleHandlerMap.put(RedisConstant.TEACHER, teacherRoleHandler);roleHandlerMap.put(RedisConstant.MANAGER, managerRoleHandler);}/*** 根據角色名稱獲取對應的處理器* @param roleName 角色名稱* @return 角色處理器* @throws TypeException 當角色不支持時拋出異常*/public RoleHandler getRoleHandler(String roleName) {RoleHandler handler = roleHandlerMap.get(roleName);if (handler == null) {throw new TypeException("不支持的用戶角色: " + roleName);}return handler;}
}

客戶端使用:

RoleHandler handler = roleHandlerFactory.getRoleHandler(role);
handler.handle(userDTO);

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

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

相關文章

Mac電腦英特爾版本最新系統15.6.1安裝php環境

Mac電腦安裝php環境 版本環境&#xff1a; 2025-08-22 14:09:19 安裝 最新系統15.6.1系統&#xff1a; 新版本的mac不帶php環境&#xff0c;需要自己 安裝 brew install php8.3 啟動說明 查看 . 使用官方方法安裝 NVM curl -o- https://raw.githubusercontent.com/nvm-sh/…

Android焦點窗口變化導致遙控鍵值監聽失效問題分析

最近在做語音全局控制Android系統功能&#xff0c;通過集成第三方語音識別sdk得到相關控制指令&#xff0c;然后將指令通過進程間通信傳遞給當前應用并作出響應。有很多通用指令&#xff0c;比如播放/暫停&#xff0c;Android系統本身就有全局控制指令&#xff1a;KeyEvent.KEY…

降本增效:基于 JavaScript 的 AI 編程 IDE 上下文壓縮優化方案

降本增效&#xff1a;基于 JavaScript 的 AI 編程 IDE 上下文壓縮優化方案 在當前 AI 輔助編程&#xff08;AI Pair Programming&#xff09;日益普及的背景下&#xff0c;開發者越來越依賴如 GitHub Copilot、Tabnine、CodeLlama 等智能編碼工具。然而&#xff0c;一個普遍存在…

DataX HdfsWriter 插件文檔

?博客主頁&#xff1a; https://blog.csdn.net/m0_63815035?typeblog &#x1f497;《博客內容》&#xff1a;大數據、Java、測試開發、Python、Android、Go、Node、Android前端小程序等相關領域知識 &#x1f4e2;博客專欄&#xff1a; https://blog.csdn.net/m0_63815035/…

Rancher 管理的 K8S 集群中部署常見應用(MySQL、Redis、RabbitMQ)并支持擴縮容的操作

文章目錄一、前提條件二、準備鏡像三、進入 Rancher UI 部署3.1. 進入 Workloads3.2. 部署 MySQL3.3. 部署 Redis3.4. 部署 RabbitMQ四、驗證服務五、擴縮容&#xff08;UI 操作&#xff09;六、附錄yml部署文件6.1. mysql.yaml6.2. redis.yaml6.3. rabbitmq.yaml一、前提條件 …

8.21-8.22網絡編程——詞典

文章目錄一、思維導圖二、詞典1、服務器2、客戶端3、現象三、牛客網刷題一、思維導圖 二、詞典 1、服務器 #include <myhead.h>#define SER_PORT 8888 //服務器端口號 #define SER_IP "192.168.116.128" //服務器IP地址 //賬戶密碼結構 typedef s…

ffmpeg測試rtsp地址

ffmpeg可以用 ffmpeg 通過 tcp協議/udp協議傳輸流到 null設備&#xff0c;ffmpeg \-rtsp_transport tcp \ # 使用TCP協議傳輸RTSP流-timeout 5000000 \ # 設置超時時間為5000000微秒&#xff08;5秒&#xff09;-i "rtsp://admin:admin123192.168.1.…

Apache Commons Math_Java科學計算的利器

1. 引言 1.1 科學計算在現代軟件開發中的重要性 隨著大數據、人工智能和科學計算需求的不斷增長,科學計算能力已成為現代軟件開發不可或缺的重要組成部分。從金融風險評估到工程仿真,從數據分析到機器學習,科學計算在各行各業中發揮著關鍵作用。 科學計算涉及復雜的數學運…

Python爬蟲框架設計:類封裝與工程化實踐?

實戰中的UA輪換技巧 import fake_useragent import random class DynamicHeader: def init(self): self.ua_generator fake_useragent.UserAgent() # 注意&#xff1a;實際使用需更新數據路徑 self.fingerprints [“chrome125”, “edge115”, “safari17”] # 2025年主流指…

5G 三卡圖傳終端:公安執法的 “移動可視化指揮中樞”

前言 在公安執法中&#xff0c;“實時取證、高效指揮、安全協同” 是破解現場復雜局面的核心需求。傳統執法設備常因傳輸卡頓、證據存證難、跨警種信息斷層等問題影響執法效能&#xff0c;而 5G 便攜式多卡高清視頻融合終端憑借多網聚合、高清編碼、安全存儲等特性&#xff0c;…

R語言rbind()和cbind()使用

rbind&#xff1a;r row&#xff08;行&#xff09;cbind&#xff1a;c column&#xff08;列&#xff09; 核心區別方向 ? rbind&#xff1a;縱向&#xff08;按行&#xff09;堆疊&#xff0c;行數相加。 ? cbind&#xff1a;橫向&#xff08;按列&#xff09;拼接&#…

【Linux】開發工具命令指南:深度解析Vim的使用操作

歡迎各位佬進行交流&#xff0c;我們一起無限進步&#xff01;&#xff01;&#xff01;&#xff01;&#xff01;&#xff01;&#xff01;&#xff01;&#xff01;&#xff01; 文章目錄Vim&#xff1a;多模式高效文本編輯器1. 初次體驗 Vim2. Vim 核心工作模式&#xff08;…

【Day 12】73.矩陣置零

文章目錄73.矩陣置零題目&#xff1a;思路&#xff1a;方法一&#xff1a;用兩個標記數組&#xff08;易理解&#xff0c;額外空間 O(mn)&#xff09;思路&#xff08;直觀&#xff09;舉例&#xff08;[[1,1,1],[1,0,1],[1,1,1]]&#xff09;優缺點代碼實現&#xff08;Go&…

Clustering Enabled Wireless Channel Modeling Using Big Data Algorithms

文章目錄Clustering TechniquesPartitioning-Based AlgorithmsDensity-Based AlgorithmsHierarchical-based algorithmsClustering Enabled Channel ModelingCluster-Based Channel ModelsClustering AlgorithmsClustering Techniques 聚類是一種已被廣泛用于數據分析的技術。…

基于「多模態大模型 + BGE向量檢索增強RAG」的兒童繪畫心理健康分析系統(vue+flask+AI算法)

一、項目演示視頻 基于「多模態大模型 BGE向量檢索增強RAG」的兒童繪畫心理健康分析系統(vueflaskAI算法)二、技術棧 前端技術棧 (web-vue) 核心框架: Vue 3.5.13 (Composition API) UI組件庫: Element Plus 2.9.4 狀態管理: Pinia 2.3.1 路由管理: Vue Router 4.5.0 HTTP客戶…

QML中的Component

目錄 &#x1f9e0; 核心概念&#xff1a;什么是 Component&#xff1f; &#x1f4ca; Component 的兩種主要形式 1. 內聯 Component&#xff08;在 QML 文件內部定義&#xff09; 2. 外部 Component&#xff08;單獨的 .qml 文件&#xff09; &#x1f3af; Component 的…

什么是模型訓練中的 特征提取,如何對光伏發電預測中的特征進行提取

&#x1f50d; 什么是模型訓練中的“特征提取” 定義&#xff1a;特征提取是從原始數據中提煉出對預測或分類最有用的信息的過程。它的目標是去掉冗余和噪聲&#xff0c;保留能最好反映數據規律的特征。 作用&#xff1a; 降低數據維度&#xff0c;減少計算量 提高模型的泛化…

Linux應急響應一般思路(三)

日志分析Linux日志分析Linux日志類型大致可以分為三類&#xff0c;內核和系統日志、用戶日志、應用日志內核和系統日志&#xff1a;這種日志主要由syslog管理、根據其配置文件/etc/syslog.conf中的設置決定內核消息和各種系統程序信息記錄到哪個位置用戶日志&#xff1a;用戶日…

【酒店酒水寄存管理效率低?】佳易王酒水寄存管理系統操作教程全解析

前言&#xff1a; &#xff08;一&#xff09;試用版獲取方式 資源下載路徑&#xff1a;進入博主頭像主頁第一篇文章末尾&#xff0c;點擊卡片按鈕&#xff1b;或訪問左上角博客主頁&#xff0c;通過右側按鈕獲取詳細資料。 說明&#xff1a;下載文件為壓縮包&#xff0c;使用…

Unity 套圈捕捉 UI 實現分享:橢圓環 Shader + 動態進度

Unity 套圈捕捉 UI 實現分享 期望表現效果 《拼貼冒險傳 / PatchQuest》 捕捉進度 動態UI實現效果 目標&#xff1a;角色 A 套圈怪物 B&#xff0c;進度環顯示圍繞角度。技術點&#xff1a;Shader 繪制橢圓環&#xff0c;支持描邊、順/逆時針,需要對兩個切口也進行描邊。 技術…