若感行文枯燥,請移步至文末Gitee地址中查看源碼自行測試感受策略模式之魅力。
一、策略模式的核心概念
策略模式的定義
定義算法族,封裝每個算法,使其可互換。
核心三要素
- Context:上下文,負責接收客戶端請求并委托具體策略對象處理,實現業務邏輯與算法實現的解耦。
- Strategy:定義接口和規范
- ConcreteStrategy:具體的實現策略
如果把策略模式想象成一個萬能遙控器,遙控器通過不同的控制卡控制不同的設備實現不同的功能;遙控器承擔Context角色,作為控制中樞提供統一操作入口;控制卡接口插槽則是對應Strategy,定義標準功能;空調、燈光、音箱控制卡則是具體的實現策略(ConcreteStrategy),各自實現溫度調節、亮度調控、音量控制等具體功能。
本質
Java中推薦面向接口編程,而非面向實現,策略模式作為這一原則的典型應用,通過抽象策略接口與具體實現解耦,有新的擴展需求時,只需要增加其實現即可,而無需對源代碼進行改動,也符合對新增開放,對修改關閉的原則(開閉原則)。基于這種設計思想,在新增設備類型時(如加濕器控制卡),只需擴展新的策略實現而無需修改遙控器本體,即無需修改原代碼,只在原代碼的基礎上新增。
模式結構解析
將策略模式的結構應用于真實且常見的業務場景如支付場景,如在門診收費頁面,用戶可以選擇支付寶、微信、銀聯支付,不同的支付方式交互的方式不同,則需要不同的支付實現策略,那么結構參考下圖:
二、解決了什么問題&應用場景
應用場景
在支付實際業務場景中,我們需要使用支持不同的支付方式如:支付寶、微信、銀聯,每種支付方式調用的接口API、請求參數、返回結果各不相同,有時系統有接入新的支付方式的需求,同時支付相關的業務邏輯比較復雜,每種支付方式的實現代碼都會比較長,尤其是聚合了多種支付方式的系統,在維護和開發時成本都更高。
解決了什么問題
策略模式解決了以下痛點:
- 代碼耦合高:不同支付方式實現混雜在業務邏輯中,存在大量
if-else/switch
分支 - 擴展成本高:新增支付方式需要修改原有支付邏輯,違反開閉原則
- 可維護性差:單個方法可能膨脹至上千行,參數傳遞混亂(如不同支付方式參數通過Map傳遞)
- 測試便利性: 新增策略時可以直接測試新邏輯,不影響原邏輯
代碼示例
使用偽代碼展示當業務邏輯復雜時,if、switch、策略模式各自的實現方案。
if-else
@Slf4j
@Service
public class IfPaymentServiceImpl implements IfPaymentService {@Overridepublic String pay(String type, BigDecimal amount) {if (Constant.PAYConstant.ALI_PAY.equals(type)) {return "支付寶支付成功,金額:" + amount;} else if (Constant.PAYConstant.WECHAT_PAY.equals(type)) {return "微信支付成功,金額:" + amount;} else if (Constant.PAYConstant.UNION_PAY.equals(type)) {return "銀聯支付成功,金額:" + amount;}throw new IllegalArgumentException("無效支付方式");}
}
switch-case
public class SwitchPaymentServiceImpl implements SwitchPaymentService {@Overridepublic String pay(String type, BigDecimal amount) {switch (type) {case Constant.PAYConstant.ALI_PAY:return "支付寶支付成功,金額:" + amount;case Constant.PAYConstant.WECHAT_PAY:return "微信支付成功,金額:" + amount;case Constant.PAYConstant.UNION_PAY:return "銀聯支付成功,金額:" + amount;default:throw new IllegalArgumentException("無效支付方式");}}
}
策略模式
支付方式的策略工廠,類比于使遙控器找到對應的功能的控制卡。
/*** 支付方式的策略工廠*/
@Slf4j
@Component
public class PaymentStrategyFactory {/*** 策略池*/private final Map<String, PaymentService> STRATEGY_MAP = new ConcurrentHashMap<>();@Resourceprivate List<PaymentService> strategies;/*** Spring啟動時注入所有的支付策略*/@PostConstructpublic void initStrategies() {for (PaymentService strategy : strategies) {log.info("注入策略:{}", strategy.getClass().getSimpleName());String type = strategy.getClass().getSimpleName().replace("Strategy", "");STRATEGY_MAP.put(type, strategy);}}/*** 根據上下文獲取支付策略* @param type 上下文參數* @return 支付策略*/public PaymentService getStrategy(String type) {PaymentService paymentService = STRATEGY_MAP.get(type);return Optional.ofNullable(paymentService).orElseThrow(() -> new IllegalArgumentException("無效支付類型"));}}
類比于遙控器中插槽,定義標準功能。
public interface PaymentService {/*** 支付接口*/String pay(String type, BigDecimal amount);
}
具體實現策略,指定遙控器可以控制設備的具體功能的視線方式。
@Slf4j
@Component
public class AlipayStrategy implements PaymentService {@Overridepublic String pay(String type, BigDecimal amount) {try {Thread.sleep(2000);} catch (Exception e) {log.info("異常", e);}return "支付寶支付成功,金額:" + amount;}
}
代碼地址
源碼