策略模式與工廠模式的黃金組合:從設計到實戰

策略模式和工廠模式是軟件開發中最常用的兩種設計模式,當它們結合使用時,能產生1+1>2的效果。本文將通過實際案例,闡述這兩種模式的協同應用,讓代碼架構更優雅、可維護性更強。

一、為什么需要組合使用?

單獨使用的痛點
  • 策略模式:客戶端需要知道所有策略類,并手動創建策略實例
  • 工廠模式:單獨使用時主要解決對象創建問題,不涉及算法切換
組合后的優勢
  1. 徹底解耦:客戶端無需知道策略類的存在和創建方式
  2. 一鍵切換:通過工廠統一管理策略實例,實現算法動態切換
  3. 集中管理:策略的注冊、創建、緩存集中在工廠類,便于維護

二、核心實現:支付系統案例

1. 策略接口定義(Strategy)
// 支付策略接口
public interface PaymentStrategy {String pay(double amount);String getStrategyName();
}
2. 具體策略實現(Concrete Strategy)
// 支付寶支付策略
public class AlipayStrategy implements PaymentStrategy {@Overridepublic String pay(double amount) {return "支付寶支付" + amount + "元,訂單號:ALIPAY-" + System.currentTimeMillis();}@Override public String getStrategyName() { return "支付寶"; }
}// 微信支付策略
public class WechatPayStrategy implements PaymentStrategy {@Overridepublic String pay(double amount) {return "微信支付" + amount + "元,訂單號:WECHAT-" + System.currentTimeMillis();}@Override public String getStrategyName() { return "微信支付"; }
}
3. 工廠模式實現(Factory)
public class PaymentStrategyFactory {// 策略緩存(單例模式+工廠模式)private static final Map<String, PaymentStrategy> STRATEGY_CACHE = new HashMap<>();private static final PaymentStrategyFactory INSTANCE = new PaymentStrategyFactory();private PaymentStrategyFactory() {// 注冊所有策略(可從配置文件加載)registerStrategy("ALIPAY", new AlipayStrategy());registerStrategy("WECHAT", new WechatPayStrategy());}// 注冊策略public void registerStrategy(String type, PaymentStrategy strategy) {STRATEGY_CACHE.put(type, strategy);}// 獲取策略(工廠核心方法)public PaymentStrategy getStrategy(String type) {if (!STRATEGY_CACHE.containsKey(type)) {throw new IllegalArgumentException("不支持的支付方式:" + type);}return STRATEGY_CACHE.get(type);}// 獲取工廠實例(單例)public static PaymentStrategyFactory getInstance() {return INSTANCE;}
}
4. 上下文類(Context)

(這里通過Context調用工廠還是非常有必要的,可以參考另外一篇:工廠模式中使用Map管理策略實例時,為何仍需要Context?)

public class PaymentContext {private final PaymentStrategyFactory factory;private PaymentStrategy strategy;public PaymentContext(PaymentStrategyFactory factory) {this.factory = factory;}// 通過工廠設置策略public void setStrategy(String type) {this.strategy = factory.getStrategy(type);}// 執行支付public String executePayment(double amount) {return strategy.pay(amount);}
}
5. 客戶端調用(Client)
public class Client {public static void main(String[] args) {// 獲取工廠實例PaymentStrategyFactory factory = PaymentStrategyFactory.getInstance();// 創建上下文并傳入工廠PaymentContext context = new PaymentContext(factory);// 使用支付寶支付context.setStrategy("ALIPAY");String result = context.executePayment(299.5);System.out.println(result);// 動態切換為微信支付context.setStrategy("WECHAT");result = context.executePayment(19.9);System.out.println(result);}
}

三、組合模式的類圖解析

1
n
1
1
1
1
PaymentStrategy
+pay(amount: double)
+getStrategyName()
AlipayStrategy
+pay(amount: double)
+getStrategyName()
WechatPayStrategy
+pay(amount: double)
+getStrategyName()
PaymentStrategyFactory
-STRATEGY_CACHE: Map
-INSTANCE: PaymentStrategyFactory
+registerStrategy(type: String, strategy: PaymentStrategy)
+getStrategy(type: String)
+getInstance()
PaymentContext
-factory: PaymentStrategyFactory
-strategy: PaymentStrategy
+setStrategy(type: String)
+executePayment(amount: double)

核心關系

  1. 工廠類創建并管理策略實例
  2. 上下文類通過工廠獲取策略
  3. 客戶端只需與上下文和工廠交互,無需接觸具體策略類

四、組合模式的優勢:比單獨使用強在哪?

1. 客戶端代碼簡化對比

單獨使用策略模式(需要手動創建策略)

// 客戶端需要知道具體策略類并手動創建
PaymentContext context = new PaymentContext(new AlipayStrategy());

結合工廠模式(通過工廠獲取策略)

// 客戶端無需知道策略類,只需傳入類型
context.setStrategy("ALIPAY");
2. 策略管理集中化
  • 策略注冊、創建、緩存都在工廠類中完成
  • 支持策略的熱插拔(如從配置文件動態加載策略)
3. 支持高級特性
  • 策略實例緩存(避免重復創建)
  • 策略版本管理(如支付寶策略升級時不影響客戶端)
  • 策略權限控制(通過工廠限制可用策略)

五、高級應用:策略工廠的擴展實現

1. 枚舉策略工廠(更簡潔的實現)
public enum PaymentStrategyEnum {ALIPAY(new AlipayStrategy()),WECHAT(new WechatPayStrategy());private final PaymentStrategy strategy;PaymentStrategyEnum(PaymentStrategy strategy) {this.strategy = strategy;}public PaymentStrategy getStrategy() {return strategy;}// 通過類型獲取策略public static PaymentStrategy getStrategy(String type) {for (PaymentStrategyEnum e : values()) {if (e.name().equals(type)) {return e.strategy;}}throw new IllegalArgumentException("不支持的策略:" + type);}
}// 客戶端調用
PaymentStrategy strategy = PaymentStrategyEnum.getStrategy("ALIPAY");
2. 基于注解的策略工廠(自動化注冊)
// 策略注解
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface Strategy {String value();
}// 策略實現類
@Strategy("ALIPAY")
public class AlipayStrategy implements PaymentStrategy { /*...*/ }// 工廠類(通過反射自動注冊策略)
public class AutoRegisterStrategyFactory {private static final Map<String, PaymentStrategy> STRATEGY_MAP = new HashMap<>();static {// 掃描所有帶@Strategy注解的類并注冊List<Class<?>> strategyClasses = ClassScanner.scan("com.example.strategy");for (Class<?> clazz : strategyClasses) {if (clazz.isAnnotationPresent(Strategy.class)) {Strategy annotation = clazz.getAnnotation(Strategy.class);try {PaymentStrategy strategy = (PaymentStrategy) clazz.getDeclaredConstructor().newInstance();STRATEGY_MAP.put(annotation.value(), strategy);} catch (Exception e) {throw new RuntimeException("策略注冊失敗", e);}}}}// ... 獲取策略方法
}

六、實戰場景:電商平臺的策略組合應用

場景描述

電商平臺需要實現:

  1. 多種支付策略(支付寶、微信、銀聯)
  2. 多種促銷策略(滿減、打折、優惠券)
  3. 多種配送策略(普通快遞、加急快遞、自提)
組合模式架構
客戶端層
上下文層
策略工廠層
創建
創建
創建
OrderService
OrderContext
支付策略
PaymentStrategyFactory
促銷策略
PromotionStrategyFactory
配送策略
DeliveryStrategyFactory

優勢

  • 訂單處理邏輯與具體策略解耦
  • 新增支付/促銷/配送策略時無需修改訂單核心代碼
  • 工廠類可統一處理策略的權限控制、日志記錄等橫切關注點

七、組合模式的注意事項

  1. 策略類型的一致性

    • 工廠返回的策略必須實現同一接口,避免類型錯誤
    • 可通過泛型約束策略類型:
      public interface Strategy<T> { /*...*/ }
      public class StrategyFactory<T extends Strategy> { /*...*/ }
      
  2. 策略實例的線程安全性

    • 若策略是無狀態的(如支付策略),可共享同一個實例
    • 若策略有狀態,需為每個上下文創建獨立實例
  3. 策略版本控制

    • 可在工廠中實現策略的版本管理,如:
      // 獲取指定版本的策略
      public PaymentStrategy getStrategy(String type, int version) { /*...*/ }
      

八、總結:策略+工廠的核心價值

這兩種模式的組合遵循了以下設計原則:

  • 開閉原則:新增策略無需修改工廠和上下文
  • 依賴倒置原則:客戶端依賴抽象(策略接口)而非具體實現
  • 單一職責原則:策略類專注算法實現,工廠類專注對象創建

在實際開發中,如果遇到以下場景時,可考慮使用策略+工廠的組合模式:

  1. 系統中有多個算法族,且需要動態切換
  2. 希望將算法的創建和使用分離
  3. 避免在客戶端代碼中出現大量策略類的實例化邏輯

通過這種組合,可以構建出更加靈活、可擴展的系統架構,讓代碼在面對需求變化時更加從容。

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

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

相關文章

SAP PP模塊與MM模塊作用詳解

SAP PP模塊與MM模塊作用詳解 一、PP模塊&#xff08;Production Planning&#xff09;—— 生產計劃與執行中樞 核心作用&#xff1a;將銷售需求轉化為可執行的生產指令&#xff0c;管控從計劃到完工的全過程。 關鍵功能 功能說明業務價值主數據管理維護BOM&#xff08;物料…

Linux tcp_info:監控TCP連接的秘密武器

深入解析 Linux tcp_info&#xff1a;TCP 狀態的實時監控利器 在開發和運維網絡服務時&#xff0c;我們常常遇到這些問題&#xff1a; 我的 TCP 連接為什么速度慢&#xff1f;是發生了重傳&#xff0c;還是窗口太小&#xff1f;擁塞控制到底有沒有生效&#xff1f; 這些問題…

CVE-2015-5531源碼分析與漏洞復現(Elasticsearch目錄遍歷漏洞)

概述 漏洞名稱&#xff1a;Elasticsearch 快照API目錄遍歷漏洞 CVE 編號&#xff1a;CVE-2015-5531 CVSS 評分&#xff1a;7.5 影響版本&#xff1a; Elasticsearch 1.0.0–1.6.0&#xff08;1.5.1及以前版本無需配置即可觸發&#xff1b;1.5.2–1.6.0需配置path.repo&#xf…

HexHub開發運維利器Database, Docker, SSH, SFTP

支持隧道&#xff0c;SFTP&#xff0c;X11轉發&#xff0c;跳板機&#xff0c;分屏廣播輸入&#xff0c;LRZSZ&#xff0c;TRZSZ&#xff0c;SCP 分屏廣播輸入 管理多臺服務器&#xff0c;更快一步 支持多種文件傳輸協議 支持跨服務器文件傳輸&#xff0c;使用復制粘貼即可進…

2025年教育、心理健康與信息管理國際會議(EMHIM 2025)

2025 2nd International Conference on Education, Mental Health, and Information Management 一、大會信息 會議簡稱&#xff1a;EMHIM 2025 大會地點&#xff1a;中國三亞 收錄檢索&#xff1a;提交Ei Compendex,CPCI,CNKI,Google Scholar等 二、會議簡介 第二屆教…

數字孿生技術為UI前端注入新活力:實現智能化交互新體驗

hello寶子們...我們是艾斯視覺擅長ui設計、前端開發、數字孿生、大數據、三維建模、三維動畫10年經驗!希望我的分享能幫助到您!如需幫助可以評論關注私信我們一起探討!致敬感謝感恩! 在數字化轉型的深水區&#xff0c;數字孿生技術正以破竹之勢重構 UI 前端的技術邏輯與交互范式…

組件協作模式

目錄 “組件協作”模式模板方法模式動機模式定義結構要點總結 “組件協作”模式 現代軟件專業分工之后的第一個結果是“框架與應用程序的劃分”。“組件協作”模式通過晚期綁定&#xff0c;實現框架與應用程序之間的松耦合&#xff0c;是二者之間協作時常用的模式。典型模式&a…

Docker 運行RAGFlow 搭建RAG知識庫

借鑒視頻&#xff1a;DeepSeek 10分鐘完全本地部署 保姆級教程 斷網運行 無懼隱私威脅 大語言模型 CPU GPU 混合推理32B輕松本地部署&#xff01;DeepSeek模擬王者&#xff01;&#xff01;_嗶哩嗶哩_bilibili 借鑒博客&#xff1a;RAGFlow搭建全攻略&#xff1a;從入門到精通…

python編寫腳本每月1號和15號執行一次將TRX是否強更發送到釘釘

編寫腳本 import requests import json import time import hmac import hashlib import base64 import urllib.parse# 1. 配置釘釘機器人 webhook "https://oapi.dingtalk.com/robot/send?access_tokenXXXXXX" secret "XXXXXXXX" # 如果沒有加簽驗…

Linux-系統管理

[rootlocalhost ~]# lscpu //查看cpu [rootlocalhost etc]# cat /etc/redhat-release //查看當前目錄的版本信息 [rootlocalhost ~]# ifconfig //查看當前激活的網卡信息 [rootlocalhost ~]# ifconfig ens33 192.168.1.10 //給網卡配置臨時地址 [rootlocalhost ~]# hostnam…

【Spring】系統化的 Spring Boot 全棧學習教程,涵蓋基礎配置、核心功能、進階實戰及文檔自動生成

這里寫目錄標題 &#x1f6e0;? **一、環境搭建與項目創建**1. 開發環境準備2. 創建第一個項目&#xff08;Spring Initializr&#xff09; &#x1f680; **二、核心功能開發**1. RESTful API 開發2. 數據持久化&#xff08;Spring Data JPA&#xff09;3. 配置文件多環境切換…

Discrete Audio Tokens: More Than a Survey

文章目錄 模型設計的考慮量化的方式&#xff1a;比特率&#xff1a;Fixed vs. Adaptive Bitrate碼本內容設計的考慮Streamability. 模型評估Reconstruction Evaluation and Complexity Analysis.識別和生成任務&#xff08;SE, SR)Acoustic Language Modeling.Music Generation…

設計在線教育項目核心數據庫表

1 在線教育項目核心數據庫表設計-ER圖 簡介&#xff1a;設計在線教育的核心庫表結構 在線教育站點速覽 xdclass.net ER圖知識回顧&#xff1a; 實體對象&#xff1a;矩形屬性&#xff1a;橢圓關系&#xff1a;菱形 核心庫表 videochapterepisodeuservideo_ordervideo_banner…

【音視頻】Ubuntu下配置ffmpeg庫

一、下載預編譯的庫 在github上可以找到編譯好的ffmpeg&#xff0c;多個版本的都有&#xff0c;這里我下載ffmpeg編譯好的動態庫 倉庫鏈接&#xff1a;(https://github.com/BtbN/FFmpeg-Builds/releases 下載后解壓得到 二、配置環境變量 打開.bashrc配置文件&#xff0c;添…

equine在神經網絡中建立量化不確定性

?一、軟件介紹 文末提供程序和源碼下載 眾所周知&#xff0c;用于監督標記問題的深度神經網絡 &#xff08;DNN&#xff09; 可以在各種學習任務中產生準確的結果。但是&#xff0c;當準確性是唯一目標時&#xff0c;DNN 經常會做出過于自信的預測&#xff0c;并且無論測試數…

C++動態鏈接庫之非托管封裝Invoke,供C#/C++ 等編程語言使用,小白教程——C++動態鏈接庫(一)

目錄&#xff1a; 一、前言及背景1.1需求描述1.2應用背景 二、編程基礎知識2.1非托管方式交互邏輯2.2該方式下C 與C# 數據轉換對應2.3VS工程下的注意點2.4C封裝接口2.4.1 __declspec(dllexport) 方式2.4.2 .def 文件方式2.4.3結合使用&#xff08;高級&#xff09; 2.5C# 封裝接…

消息隊列的網絡模型詳解:IO多路復用、Reactor模型、零拷貝

文章目錄 一、消息隊列的網路模型擬解決問題單個請求性能優化1. 編解碼速度2. 網絡模塊處理速度 并發請求性能優化1. 高效的連接管理2. 快速處理高并發請求3. 大流量場景處理 二、一些技術基礎知識1. 基于多路復用技術管理 TCP 連接&#xff08;提高性能&#xff09;&#xff0…

【生成模型】【模型介紹】(一)視頻生成Wan2.1速度質量簡單評測

基礎模型&#xff1a;FramePack https://github.com/kijai/ComfyUI-FramePackWrapper huggingface-cli download Comfy-Org/HunyuanVideo_repackaged --local-dir Comfy-Org/HunyuanVideo_repackaged --resume-download huggingface-cli download Comfy-Org/sigclip_vision_3…

微信小程序之滑塊scroll-view

我們要做的東西&#xff1a; 滑塊的視頻 我們先做個基本的圖片和文字(wxm;)&#xff1a; <scroll-view><view class"scrollItem"><image src"https://bkimg.cdn.bcebos.com/pic/fc1f4134970a304e251fd88e8191b086c9177f3ef634?x-bce-processim…

如何寫出優秀的單元測試?

&#x1f345; 點擊文末小卡片&#xff0c;免費獲取軟件測試全套資料&#xff0c;資料在手&#xff0c;漲薪更快 寫出優秀的單元測試需要考慮以下幾個方面&#xff1a; 1. 測試用例設計 測試用例應該覆蓋被測試代碼的不同場景和邊界情況&#xff0c;以盡可能發現潛在的問題。…