策略模式 + 工廠模式

策略模式:

簡單來說解決的行為的封裝與選擇。如HandlerMapping,將 HTTP 請求映射到對應的處理器(Controller 或方法)。

工廠模式:

解決的是具有相同屬性的對象創建問題,如BeanFactory創建bean對象。

解決的代碼問題:

// 1. 定義具體支付類,但沒有統一的接口
public class Alipay {public void pay(double amount) {System.out.println("使用支付寶支付:" + amount + "元");// 調用支付寶SDK的具體邏輯}
}public class WechatPay {public void executePayment(double amount) { // 方法名都不統一System.out.println("使用微信支付:" + amount + "元");// 調用微信支付SDK的具體邏輯}
}// 2. 客戶端代碼直接創建具體對象并調用
public class PaymentService {public void processPayment(String paymentType, double amount) {if ("alipay".equalsIgnoreCase(paymentType)) {Alipay alipay = new Alipay(); // 直接依賴具體類Alipayalipay.pay(amount);} else if ("wechat".equalsIgnoreCase(paymentType)) {WechatPay wechatPay = new WechatPay(); // 直接依賴具體類WechatPaywechatPay.executePayment(amount); // 方法名不統一,增加使用難度} else {throw new IllegalArgumentException("不支持的支付方式");}// 如果日后要為Alipay的創建增加緩存、初始化等復雜邏輯,這里會變得臃腫}
}// 3. 另一個服務也可能需要創建支付對象,導致代碼重復
public class OrderService {public void createOrder(String paymentType) {// ... 訂單創建邏輯// 又一套if-else來判斷支付類型并創建對象if ("alipay".equalsIgnoreCase(paymentType)) {Alipay alipay = new Alipay(); // 創建邏輯重復// ... 可能還有其他操作} else if ("wechat".equalsIgnoreCase(paymentType)) {WechatPay wechatPay = new WechatPay();// ...}}
}

問題:

  • ?高耦合(Tight Coupling)??:PaymentServiceOrderService等客戶端代碼直接依賴具體的支付類(Alipay, WechatPay)。一旦這些具體類發生變化(如構造函數改變),所有創建它們的地方都需要修改

  • ?違反開閉原則(Violates Open/Closed Principle)??:當需要增加一個新的支付方式(如UnionPay銀聯支付)時,?必須修改所有包含支付類型判斷 if-else分支的客戶端代碼(如 PaymentService, OrderService)。這使得系統難以擴展,也容易在修改時引入錯誤

  • ?代碼重復(Code Duplication)??:對象的創建邏輯分散在應用程序的多個地方。如果創建過程很復雜(例如需要配置密鑰、初始化連接等),這些重復的代碼會難以維護

  • ?可讀性和可維護性差(Poor Readability and Maintainability)??:客戶端代碼中充斥著具體的實例化操作和類型判斷,?掩蓋了核心的業務邏輯,使得代碼難以理解和維護

  • ?難以測試(Hard to Test)??:由于客戶端直接實例化具體對象,在進行單元測試時,很難模擬(Mock)?? 這些依賴,從而難以隔離測試目標單元

策略模式解決的代碼問題:

// ? 未使用策略模式的支付處理函數 - 圈復雜度高,難以維護
public class PaymentService {public void processPayment(String paymentType, double amount) {if ("alipay".equalsIgnoreCase(paymentType)) {System.out.println("調用支付寶SDK,支付¥" + amount);// 實際的支付寶支付邏輯,可能很復雜,包括參數組裝、加密、調用網關等} else if ("wechat".equalsIgnoreCase(paymentType)) {System.out.println("調用微信支付SDK,支付¥" + amount);// 實際的微信支付邏輯} else if ("creditCard".equalsIgnoreCase(paymentType)) {System.out.println("調用銀聯接口,支付¥" + amount);// 實際的信用卡支付邏輯,可能包括卡號驗證、有效期檢查、3D認證等} else if ("applePay".equalsIgnoreCase(paymentType)) {System.out.println("調用Apple Pay API,支付¥" + amount);// 實際的Apple Pay支付邏輯} else {throw new IllegalArgumentException("不支持的支付方式: " + paymentType);}// 未來新增一種支付方式(如數字貨幣),就必須修改這個函數,增加一個else if分支}
}

問題:

  • ?違反開閉原則?:每當需要增加一種新的支付方式(例如 unionPay(銀聯)或 digitalCurrency(數字貨幣)),你都必須修改這個 processPayment函數的內部邏輯,增加一個新的 else if分支。這違反了面向對象設計原則中的“對擴展開放,對修改關閉”的原則。

  • ?代碼臃腫,可讀性差?:所有的支付邏輯都堆積在一個方法里。如果每種支付方式的邏輯都很復雜(例如涉及不同的參數組裝、加密算法、第三方API調用),這個方法會變得非常長,難以閱讀和理解。

  • ?可維護性低?:不同支付方式的邏輯相互糾纏。修改一種支付方式的邏輯時,可能會無意中影響到其他支付方式的代碼(雖然邏輯上獨立,但物理上靠近,容易誤觸)。調試時也需要在這個龐大的函數中一步步跟蹤。

  • ?難以測試?:要為這個 processPayment方法編寫單元測試,你需要覆蓋所有的 if-else分支,測試用例會又長又復雜。你很難模擬(Mock)各種支付方式的具體實現,因為它們都緊耦合在這個方法里。

  • ?重復代碼?:如果其他業務邏輯(如退款、查詢訂單)也需要根據支付類型進行類似的判斷,那么同樣的 if-else語句可能會散布在代碼庫的多個地方,導致代碼重復。

正確的使用樣例步驟:

  1. 定義策略接口,策略接口共同方法
  2. 實現策略接口的具體實現類
  3. 定義工廠類,并設置緩存map(鍵為策略類型(即Bean名稱),值為對應的策略實例)
  4. 可設置監控,控制策略的注冊

策略接口

package com.luojie.strategy;/*** 支付策略接口* <p>* 這是策略模式的核心接口,定義了所有支付策略必須實現的共同方法。* 通過這個接口,不同的支付方式可以被統一對待,實現了策略的封裝和替換。* </p>* <p>* 在策略模式中,這個接口扮演了"策略"角色,定義了算法族的共同接口,* 任何具體的支付方式都需要實現這個接口,提供自己的支付邏輯。* </p>*/
public interface PaymentStrategy {/*** 支付方法* <p>* 所有支付策略都必須實現的核心方法,用于執行具體的支付操作。* 不同的支付策略(如支付寶、微信支付、銀聯支付)會提供各自不同的實現。* </p>* @param amount 支付金額,使用double類型表示* @return 支付結果,返回一個描述支付過程的字符串信息*/String pay(double amount);
}

策略實現類--支付寶

package com.luojie.strategy;import org.springframework.stereotype.Component;/*** 支付寶支付策略實現* <p>* 這是支付策略接口的具體實現類,專門處理支付寶支付邏輯。* 在策略模式中,這個類扮演了"具體策略"角色,實現了策略接口定義的算法。* </p>* <p>* 通過Spring的@Component注解將該類標記為Spring組件,* 并指定Bean名稱為"alipay",這樣策略工廠可以通過這個名稱來獲取該策略實例。* </p>*/
@Component("alipay")  // 將該策略注冊為Spring Bean,名稱為"alipay"
public class AlipayStrategy implements PaymentStrategy {/*** 實現支付寶支付邏輯* <p>* 該方法提供了使用支付寶進行支付的具體實現。* 在實際應用中,這里會包含與支付寶API交互的代碼,* 如構建支付請求、調用支付寶SDK、處理支付結果等。* </p>* <p>* 當前示例為了演示策略模式的基本結構,使用了簡化的實現,* 僅返回一個描述支付過程的字符串。* </p>* @param amount 支付金額* @return 支付結果描述*/@Overridepublic String pay(double amount) {// 實際應用中,這里會包含真實的支付寶支付邏輯// 例如調用支付寶API、處理支付請求等return "使用支付寶支付了" + amount + "元";}
}

策略實現類--銀聯支付

package com.luojie.strategy;import org.springframework.stereotype.Component;/*** 銀聯支付策略實現* <p>* 這是支付策略接口的具體實現類,專門處理銀聯支付邏輯。* 在策略模式中,這個類扮演了"具體策略"角色,實現了策略接口定義的算法。* </p>* <p>* 通過Spring的@Component注解將該類標記為Spring組件,* 并指定Bean名稱為"unionPay",這樣策略工廠可以通過這個名稱來獲取該策略實例。* </p>*/
@Component("unionPay")  // 將該策略注冊為Spring Bean,名稱為"unionPay"
public class UnionPayStrategy implements PaymentStrategy {/*** 實現銀聯支付邏輯* <p>* 該方法提供了使用銀聯支付進行支付的具體實現。* 在實際應用中,這里會包含與銀聯支付API交互的代碼,* 如構建支付請求、調用銀聯支付SDK、處理支付結果等。* </p>* <p>* 當前示例為了演示策略模式的基本結構,使用了簡化的實現,* 僅返回一個描述支付過程的字符串。* </p>* @param amount 支付金額* @return 支付結果描述*/@Overridepublic String pay(double amount) {// 實際應用中,這里會包含真實的銀聯支付邏輯// 例如調用銀聯支付API、處理支付請求等return "使用銀聯支付了" + amount + "元";}
}

策略實現類--微信支付

package com.luojie.strategy;import org.springframework.stereotype.Component;/*** 微信支付策略實現* <p>* 這是支付策略接口的具體實現類,專門處理微信支付邏輯。* 在策略模式中,這個類扮演了"具體策略"角色,實現了策略接口定義的算法。* </p>* <p>* 通過Spring的@Component注解將該類標記為Spring組件,* 并指定Bean名稱為"wechatPay",這樣策略工廠可以通過這個名稱來獲取該策略實例。* </p>*/
@Component("wechatPay")  // 將該策略注冊為Spring Bean,名稱為"wechatPay"
public class WechatPayStrategy implements PaymentStrategy {/*** 實現微信支付邏輯* <p>* 該方法提供了使用微信支付進行支付的具體實現。* 在實際應用中,這里會包含與微信支付API交互的代碼,* 如構建支付請求、調用微信支付SDK、處理支付結果等。* </p>* <p>* 當前示例為了演示策略模式的基本結構,使用了簡化的實現,* 僅返回一個描述支付過程的字符串。* </p>* @param amount 支付金額* @return 支付結果描述*/@Overridepublic String pay(double amount) {// 實際應用中,這里會包含真實的微信支付邏輯// 例如調用微信支付API、處理支付請求等return "使用微信支付了" + amount + "元";}
}

工廠類

package com.luojie.strategy;import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;import com.luojie.config.StrategyConfig.StrategyConfigurationInfo;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;/*** 支付策略工廠* <p>* 這是工廠模式與策略模式結合使用的核心類,負責管理和提供各種支付策略實例。* 在策略模式中,這個類扮演了"策略選擇器"的角色,客戶端通過工廠來獲取具體策略,* 而不需要直接實例化具體策略類,從而實現了客戶端與具體策略的解耦。* </p>* <p>* 通過Spring的依賴注入機制和StrategyConfigurationInfo配置,該工廠能夠根據配置* 決定是否自動收集所有實現了PaymentStrategy接口的Bean,提供了更靈活的策略管理方式。* </p>*/
@Component  // 注冊為Spring組件,使其能夠被自動發現和注入
public class PaymentStrategyFactory {// 日志記錄器,用于記錄工廠的操作日志private static final Logger logger = LoggerFactory.getLogger(PaymentStrategyFactory.class);// 使用ConcurrentHashMap存儲所有策略實現,保證線程安全// 鍵為策略類型(即Bean名稱),值為對應的策略實例private final Map<String, PaymentStrategy> strategyMap = new ConcurrentHashMap<>();// 注入策略配置信息,用于控制策略的自動注冊行為private final StrategyConfigurationInfo configInfo;/*** 構造函數,注入策略配置信息和所有策略實現* <p>* 根據StrategyConfigurationInfo中的autoRegisterStrategies配置決定是否自動注冊所有策略。* 這樣可以靈活控制策略的管理方式。* </p>* @param strategyMap 包含所有策略實現的Map,由Spring自動注入* @param configInfo 策略配置信息,控制自動注冊行為*/@Autowiredpublic PaymentStrategyFactory(Map<String, PaymentStrategy> strategyMap, StrategyConfigurationInfo configInfo) {this.configInfo = configInfo;// 根據配置決定是否自動注冊所有策略if (configInfo != null && configInfo.isAutoRegisterStrategies()) {this.strategyMap.putAll(strategyMap);// 記錄策略注冊信息,便于調試和監控logger.info("支付策略工廠初始化完成,共自動加載了{}種支付策略", strategyMap.size());logger.info("已加載的支付策略類型:{}", strategyMap.keySet());} else {logger.info("支付策略工廠初始化完成,策略自動注冊功能已禁用");}}/*** 手動注冊支付策略* <p>* 當autoRegisterStrategies設置為false時,可以通過此方法手動注冊策略。* 這提供了更精細的策略管理控制。* </p>* @param strategyType 策略類型(唯一標識符)* @param strategy 策略實現實例* @return 當前工廠實例,支持鏈式調用*/public PaymentStrategyFactory registerStrategy(String strategyType, PaymentStrategy strategy) {if (strategyType == null || strategy == null) {logger.error("注冊策略失敗:策略類型或策略實例不能為空");throw new IllegalArgumentException("策略類型或策略實例不能為空");}strategyMap.put(strategyType, strategy);logger.info("手動注冊支付策略成功:{}", strategyType);return this;}/*** 移除已注冊的支付策略* <p>* 提供移除策略的功能,便于動態調整可用的支付方式。* </p>* @param strategyType 要移除的策略類型* @return 被移除的策略實例,如果不存在則返回null*/public PaymentStrategy unregisterStrategy(String strategyType) {PaymentStrategy removedStrategy = strategyMap.remove(strategyType);if (removedStrategy != null) {logger.info("移除支付策略成功:{}", strategyType);}return removedStrategy;}/*** 根據策略類型獲取對應的策略實現* <p>* 這是工廠的核心方法,用于根據客戶端提供的策略類型,返回對應的策略實例。* 客戶端只需要知道策略類型(如"alipay"、"wechatPay"等),* 不需要知道具體的策略實現類,從而實現了客戶端與具體策略的解耦。* </p>* @param strategyType 策略類型(即Bean名稱)* @return 對應的策略實現實例* @throws IllegalArgumentException 如果請求的策略類型不存在*/public PaymentStrategy getStrategy(String strategyType) {// 日志記錄請求的策略類型logger.debug("請求獲取支付策略:{}", strategyType);// 從Map中獲取對應的策略實現PaymentStrategy strategy = strategyMap.get(strategyType);// 如果策略不存在,拋出異常if (strategy == null) {logger.error("不支持的支付方式:{}", strategyType);throw new IllegalArgumentException("不支持的支付方式:" + strategyType);}// 返回獲取到的策略實例logger.debug("成功獲取支付策略:{},對應的實現類:{}", strategyType, strategy.getClass().getSimpleName());return strategy;}
}

擴展的控制類

package com.luojie.config;import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;/*** 策略模式配置類* <p>* 該類是整個策略模式實現的核心配置類,主要負責:* 1. 啟用策略包的組件掃描* 2. 配置策略監控機制* 3. 提供策略配置信息管理* <p>* 通過Spring的@Configuration注解標記為配置類,確保在Spring Boot應用啟動時被自動加載* </p>*/
@Configuration
// 主組件掃描由Spring Boot自動處理,這里使用StrategyConfigurationInfo中的packageToScan進行更靈活的配置
// @ComponentScan注解本身不支持動態路徑,但我們在后續的BeanPostProcessor中使用packageToScan參數
public class StrategyConfig {// 日志記錄器,使用SLF4J框架記錄配置和監控信息private static final Logger logger = LoggerFactory.getLogger(StrategyConfig.class);/*** 構造函數,用于記錄配置類初始化信息* <p>* 在配置類實例化時記錄初始化日志,便于跟蹤系統啟動過程中的策略模式初始化狀態* </p>*/public StrategyConfig() {logger.info("策略模式配置類[StrategyConfig]初始化完成");logger.info("開始掃描策略包: com.luojie.strategy");}/*** 創建策略模式監控的BeanPostProcessor* <p>* 通過Spring的BeanPostProcessor機制,在所有Bean初始化完成后進行攔截處理,* 專門用于監控和記錄策略實現類的加載情況,幫助開發者確認所有策略都已正確注冊到Spring容器* </p>* @param strategyConfigurationInfo 策略配置信息,用于控制監控行為* @return 自定義的BeanPostProcessor實例,用于策略實現類的監控*/@Beanpublic BeanPostProcessor strategyBeanPostProcessor(StrategyConfigurationInfo strategyConfigurationInfo) {return new BeanPostProcessor() {/*** 在Bean初始化完成后進行處理* <p>* 此方法會在每個Spring Bean初始化完成后被調用,我們在這里專門處理策略包中的Bean* </p>* @param bean 初始化完成的Bean實例* @param beanName Bean在Spring容器中的名稱* @return 處理后的Bean實例(此處直接返回原實例,不做修改)* @throws BeansException Bean處理過程中的異常*/@Overridepublic Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {// 根據配置信息決定是否啟用監控if (strategyConfigurationInfo.isMonitorEnabled()) {// 檢查是否為支付策略實現類(排除配置類、工廠類和上下文類本身)// 使用配置中的packageToScan參數進行判斷,實現動態配置if (bean.getClass().getPackage() != null && strategyConfigurationInfo.getPackageToScan() != null &&bean.getClass().getPackage().getName().startsWith(strategyConfigurationInfo.getPackageToScan()) && !beanName.equals("strategyConfig") && !beanName.equals("paymentStrategyFactory") && !beanName.equals("paymentContext")) {// 記錄策略實現類的初始化和注冊信息logger.info("策略實現類[{}] (Bean名稱: {}) 初始化完成并注冊到Spring容器", bean.getClass().getSimpleName(), beanName);}}return bean;  // 返回原Bean,不做任何修改}};}/*** 獲取策略模式配置信息的方法* <p>* 創建并配置一個StrategyConfigurationInfo實例,用于封裝當前策略模式的配置狀態* 將其注冊為Spring Bean,便于在系統其他地方獲取和使用這些配置信息* </p>* <p>* 該配置實例包含三個核心參數,都有實際應用場景:* 1. packageToScan:用于策略實現類的包路徑識別,在BeanPostProcessor中使用* 2. monitorEnabled:控制是否啟用策略監控功能* 3. autoRegisterStrategies:控制策略工廠是否自動注冊所有策略* </p>* @return 配置完成的StrategyConfigurationInfo實例*/@Beanpublic StrategyConfigurationInfo strategyConfigurationInfo() {StrategyConfigurationInfo info = new StrategyConfigurationInfo();// 設置要掃描的策略包路徑 - 用于BeanPostProcessor中的策略類識別info.setPackageToScan("com.luojie.strategy");// 啟用策略監控功能 - 控制是否記錄策略實現類的加載日志info.setMonitorEnabled(true);// 啟用策略自動注冊功能 - 控制策略工廠是否自動注冊所有策略實現info.setAutoRegisterStrategies(true);// 記錄配置信息日志logger.info("策略模式配置信息: {}", info);return info;}/*** 內部類,用于封裝策略模式的配置信息* <p>* 該類作為StrategyConfig的內部類,專門用于封裝和管理策略模式的配置參數,* 提供了對策略掃描、監控和自動注冊等功能的配置管理* </p>*/public static class StrategyConfigurationInfo {// 策略實現類所在的包路徑,用于組件掃描private String packageToScan;// 是否啟用策略監控功能private boolean monitorEnabled;// 是否自動注冊策略實現到工廠類private boolean autoRegisterStrategies;/*** 獲取策略實現類所在的包路徑* @return 包路徑字符串*/public String getPackageToScan() {return packageToScan;}/*** 設置策略實現類所在的包路徑* @param packageToScan 包路徑字符串*/public void setPackageToScan(String packageToScan) {this.packageToScan = packageToScan;}/*** 獲取是否啟用策略監控功能* @return true表示啟用監控,false表示禁用監控*/public boolean isMonitorEnabled() {return monitorEnabled;}/*** 設置是否啟用策略監控功能* @param monitorEnabled true表示啟用監控,false表示禁用監控*/public void setMonitorEnabled(boolean monitorEnabled) {this.monitorEnabled = monitorEnabled;}/*** 獲取是否自動注冊策略實現* @return true表示自動注冊,false表示手動注冊*/public boolean isAutoRegisterStrategies() {return autoRegisterStrategies;}/*** 設置是否自動注冊策略實現* @param autoRegisterStrategies true表示自動注冊,false表示手動注冊*/public void setAutoRegisterStrategies(boolean autoRegisterStrategies) {this.autoRegisterStrategies = autoRegisterStrategies;}/*** 返回配置信息的字符串表示* @return 包含所有配置項的字符串*/@Overridepublic String toString() {return "StrategyConfigurationInfo{" +"packageToScan='" + packageToScan + '\'' +", monitorEnabled=" + monitorEnabled +", autoRegisterStrategies=" + autoRegisterStrategies +'}';}}
}

實際的調用類--根據type,直接調用具體的對象方法

package com.luojie.strategy;import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;/*** 支付上下文類* <p>* 這是策略模式中的上下文類,負責持有和使用策略,為客戶端提供統一的調用入口。* 在策略模式中,上下文類封裝了策略的選擇和使用細節,客戶端不需要直接與策略交互,* 只需與上下文類交互即可,從而進一步降低了客戶端與具體策略的耦合。* </p>* <p>* 該上下文類提供了兩種使用策略的方式:* 1. 先設置策略,然后執行操作(分步式)* 2. 直接指定策略類型執行操作(一步式)* </p>*/
@Component  // 注冊為Spring組件,使其能夠被自動發現和注入
public class PaymentContext {// 日志記錄器,用于記錄上下文的操作日志private static final Logger logger = LoggerFactory.getLogger(PaymentContext.class);// 策略工廠,用于獲取具體的策略實例private final PaymentStrategyFactory paymentStrategyFactory;// 當前使用的支付策略實例private PaymentStrategy currentStrategy;/*** 構造函數,注入策略工廠* <p>* 通過Spring的依賴注入機制,自動獲取PaymentStrategyFactory的實例,* 以便后續通過工廠獲取具體的策略實現。* </p>* @param paymentStrategyFactory 支付策略工廠實例*/@Autowiredpublic PaymentContext(PaymentStrategyFactory paymentStrategyFactory) {this.paymentStrategyFactory = paymentStrategyFactory;logger.info("支付上下文初始化完成");}/*** 設置支付策略* <p>* 這是分步式使用策略的第一步,用于設置后續操作要使用的支付策略。* 通過策略工廠獲取指定類型的策略實例,并存儲在當前上下文中。* </p>* @param strategyType 策略類型(如"alipay"、"wechatPay"等)*/public void setPaymentStrategy(String strategyType) {logger.debug("設置支付策略:{}", strategyType);this.currentStrategy = paymentStrategyFactory.getStrategy(strategyType);logger.info("支付策略設置成功:{}", strategyType);}/*** 執行支付操作* <p>* 這是分步式使用策略的第二步,使用已設置的支付策略執行支付操作。* 在調用此方法前,必須先調用setPaymentStrategy方法設置策略。* </p>* @param amount 支付金額* @return 支付結果描述* @throws IllegalStateException 如果未設置支付策略*/public String executePayment(double amount) {// 檢查是否已設置支付策略if (currentStrategy == null) {logger.error("執行支付失敗:未設置支付策略");throw new IllegalStateException("請先設置支付策略");}logger.debug("執行支付操作,金額:{}元,使用策略:{}", amount, currentStrategy.getClass().getSimpleName());// 調用當前策略的pay方法執行支付String result = currentStrategy.pay(amount);logger.info("支付操作執行完成,結果:{}", result);return result;}/*** 直接執行支付,一步完成策略選擇和支付操作* <p>* 這是一步式使用策略的方法,將策略選擇和執行操作合并為一步,* 適用于只需單次使用特定策略的場景,無需先設置再執行。* </p>* @param strategyType 策略類型(如"alipay"、"wechatPay"等)* @param amount 支付金額* @return 支付結果描述*/public String pay(String strategyType, double amount) {logger.debug("直接執行支付,策略類型:{},金額:{}元", strategyType, amount);// 通過工廠獲取指定的策略實例并直接調用其pay方法PaymentStrategy strategy = paymentStrategyFactory.getStrategy(strategyType);String result = strategy.pay(amount);logger.info("直接支付操作執行完成,結果:{}", result);return result;}
}

調用測試

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

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

相關文章

Diamond基礎3:在線邏輯分析儀Reveal的使用

文章目錄1. 與ILA的區別2. 使用Reveal步驟3.Reveal注意事項4.傳送門1. 與ILA的區別 Reveal是Lattice Diamond集成開發環境用于在線監測信號的工具&#xff0c;ILA是xilinx的Vivado集成開發工具的在線邏輯分析儀&#xff0c;同Reveal一樣&#xff0c;均可以在項目運行過程中&am…

超適合程序員做知識整理的 AI 網站

這次要給大家分享一個超適合程序員做知識整理的 AI 網站 ——Notion AI&#xff0c;網址是Notion&#xff0c;它能把你隨手記的雜亂筆記、代碼片段、技術文檔&#xff0c;一鍵梳理成邏輯清晰的結構化內容&#xff0c;小索奇我用它整理 “Python 爬蟲知識點” 時&#xff0c;原本…

【 Selenium 爬蟲】2025年8月25日-pixabay 圖片采集

無惡意采集&#xff0c;取部分圖片用來做相冊測試的&#x1f604; 效果圖import cn.hutool.core.io.FileUtil; import cn.hutool.core.util.StrUtil; import cn.hutool.json.JSONUtil; import com.la.selenium.utils.SeleniumUtil; import lombok.extern.slf4j.Slf4j; import o…

服務器托管需要注意什么事項?

服務器托管是企業IT基礎設施的關鍵環節&#xff0c;其穩定性和安全性直接影響業務連續性。需要注意下面這幾點&#xff01; 一、服務商與機房選擇 服務商資質 選擇持有ISP證書的合法服務商&#xff0c;優先考慮運營超5年、市場口碑佳的老牌公司&#xff0c;技術團隊需具備72…

微信小程序備忘

1.按鈕事件中想切換到tabBar中的鏈接用switchTab&#xff0c;不能用navigateTo&#xff1a;agentPage: function() { wx.switchTab({url: /pages/agent/agent}) },特別注意&#xff1a;微信小程序中所謂的自定義&#xff0c;并不是完全的自定義&#xff0c;在app.json中定義&a…

虛擬機NAT模式通過宿主機(Windows)上網不穩定解決辦法(無法上網)(將宿主機設置固定ip并配置dns)

文章目錄問題描述解決辦法分析**1. 問題的根本原因****(1) 宿主機動態IP的DNS配置問題****(2) NAT模式下的網絡依賴****(3) 自習室WiFi的潛在限制****2. 用戶操作的合理性分析****(1) 固定IP的作用****(2) 手動指定公共DNS的作用****3. 用戶懷疑的正確性****4. 其他可能原因的排…

基于 HTML、CSS 和 JavaScript 的智能圖像虛化系統

目錄 1 前言 2 技術實現 2.1 HTML&#xff1a;搭建頁面基礎結構 2.2 CSS&#xff1a;打造科技感視覺體驗 2.3 JavaScript&#xff1a;實現核心虛化功能 2.3.1 圖像上傳與初始化 2.3.2 實時虛化處理 2.3.3 圖像下載功能 3 完整代碼 4 運行結果 5 總結 1 前言 三大核…

PS更改圖像尺寸

新建文檔 1.左上角——新文件可以新建文檔2.文件——新建文檔3.快捷鍵CtrlN 對文件命名 輸入新文件名稱設置寬度和高度 設置文件的寬高&#xff0c;單位可以是像素、英寸、厘米等。還可以選擇文件方向或者是否使用畫板模式畫布背景色 一般顯示白色&#xff0c;也可以選擇其他顏…

分詞器詳解(一)

文章目錄&#x1f31f; 第0層&#xff1a;極簡版&#xff08;30秒理解&#xff09;核心公式生活比喻&#x1f4da; 第1層&#xff1a;基礎概念&#xff08;5分鐘理解&#xff09;1. 分詞器基礎1.1 分詞器的核心作用1.2 主流分詞算法對比2. 基礎實現2.1 BPE實現原理2.2 特殊標記…

推薦一個論文閱讀工具ivySCI

1.一些關于ivySCI的數據 &#xff08;摘自&#xff1a;吳焱紅&#xff0c;論文示范:ivySCI 在論文管理、閱讀和筆記中的體驗&#xff09; 1.科研人員花在文獻閱讀上的時間占總工作時間的 23%2.每年閱讀的文獻數量大概是 188 到 280 篇3.ivySCI 提供 Pad(iPad 和 Android) 和桌…

診斷服務器(Diagnostic Server)

在《SWS_Diagnostics.pdf》中,診斷服務器(Diagnostic Server) 是診斷管理(DM)的核心執行單元,聚焦 “軟件集群(SoftwareCluster)級診斷資源的獨立管控”,實現 UDS(ISO 14229-1)與 SOVD(ASAM 服務化診斷)的全流程診斷功能。以下結合文檔 7.3 節 “Diagnostic Serve…

如何開發一款高穩定、低延遲、功能全面的RTSP播放器?

一、引言&#xff1a;RTSP的價值與挑戰 RTSP&#xff08;Real-Time Streaming Protocol&#xff09;作為實時流媒體傳輸的核心協議&#xff0c;廣泛應用于安防監控、無人機回傳、教育互動、遠程醫療、單兵指揮等行業。它提供了 基于請求/響應機制的流媒體控制能力&#xff0c;…

數據結構——樹(03二叉樹,與路徑有關的問題,代碼練習)

文章目錄一、求二叉樹的值【層序遍歷實現】1.1右視圖1.2層最大值1.3層和1.4最底層的葉子結點的和1.5層平均值1.6最大層和的層號二、二叉樹的路徑2.1根節點到葉子節點&#xff0c;二叉樹的路徑2.2路徑的十進制之和 & 二進制之和2.3二叉樹里的路徑三、二叉樹的路徑23.1最長同…

Git配置:禁用全局HTTPS驗證

文章目錄Git配置&#xff1a;禁用全局HTTPS驗證什么是HTTPS驗證&#xff1f;為什么需要禁用HTTPS驗證&#xff1f;如何禁用全局HTTPS驗證&#xff1f;注意事項結論Git配置&#xff1a;禁用全局HTTPS驗證 在軟件開發和版本控制中&#xff0c;Git是一個不可或缺的工具。它幫助開…

【54頁PPT】基于DeepSeek的數據治理技術(附下載方式)

篇幅所限&#xff0c;本文只提供部分資料內容&#xff0c;完整資料請看下面鏈接 https://download.csdn.net/download/2501_92796370/91778320 資料解讀&#xff1a;《基于DeepSeek的數據治理技術》 詳細資料請看本解讀文章的最后內容。 作為數據治理領域的資深研究者&#…

2025年最新 unityHub游戲引擎開發2d手機游戲和桌面游戲教程

設置開發編輯器 &#xff1a; 以下是一個簡化版的移動控制代碼&#xff0c;不依賴自定義輸入配置&#xff0c;直接使用 Unity 新輸入系統的默認綁定&#xff0c;并兼容手機端的 Joystick Pack 虛擬搖桿&#xff1a; SimplePlayerMovement using UnityEngine; using UnityEngi…

SuperMap GIS基礎產品FAQ集錦(20250901)

一、SuperMap iDesktopX 問題1&#xff1a;咨詢MapGIS數據遷移功能是否支持MapGIS 10版本&#xff0c;在遷移10版本的符號庫時卡在0%并報錯“升級6x系統庫失敗”。 11.3.0【問題原因】客戶使用問題&#xff0c;mapgis6.7里面工程文件和符號庫之前沒有綁定關系&#xff0c;mapgi…

react-native-reanimated-carousel的API記錄

?核心屬性??data?類型: Array<any>必填&#xff0c;輪播數據源&#xff0c;支持任意類型數據。?renderItem?類型: ({ item, index }) > React.ReactNode必填&#xff0c;自定義卡片渲染函數&#xff0c;參數包含當前項和索引。?width/height?類型: number控制…

TypeScript 泛型入門(新手友好、完整詳解)

目標讀者&#xff1a;剛學 TS 的前端開發者&#xff0c;或希望把泛型用到實際工程&#xff08;請求封裝、組件復用&#xff09;中的同學。目錄 為什么需要泛型&#xff08;直觀動機&#xff09;基本語法與例子&#xff08;函數、接口、類&#xff09;泛型約束&#xff08;exten…

Linux ARP老化機制/探測機制/ip neigh使用

文章目錄1. ARP狀態機1.1 ARP狀態類型1.2 狀態轉換圖2. 超時時間與參數2.1 主要超時參數2.1.1 基礎時間參數2.1.2 探測相關參數2.1.3 垃圾回收參數3. 主機發送ARP報文的時機3.1 發送數據包時發現ARP緩存中沒有目標IP的MAC地址3.2 ARP條目進入STALE狀態后需要發送數據3.3 定期維…