策略模式(Strategy Pattern)
一句话理解
策略模式 = “interchangeable algorithms”,定义一系列算法,把它们一个个封装起来,并且使它们可以互相替换。
就像去餐厅,你可以选择微信支付、支付宝、刷卡,不同的支付方式就是不同的"策略"。
【核心思想】
把不同的算法/行为封装成独立的类,让它们可以互相替换。
客户端不需要知道具体使用哪个算法,只需要调用统一的接口。
【为什么要用策略模式?】
❌ 不用策略模式时,代码是这样的:
publicclassPaymentService{publicvoidpay(Stringtype,BigDecimalamount){if("alipay".equals(type)){// 支付宝支付逻辑(50行代码)System.out.println("支付宝支付...");}elseif("wechat".equals(type)){// 微信支付逻辑(50行代码)System.out.println("微信支付...");}elseif("bank".equals(type)){// 银行卡支付逻辑(50行代码)System.out.println("银行卡支付...");}// 每加一种支付方式,这里就要加一堆 if-else// 类越来越臃肿,修改一个支付方式可能影响其他方式// 老板:再加个云闪付!// 你:又要改这个类... 😭}}✅ 使用策略模式后:
// 每种支付方式一个类,独立维护// 新增支付方式?新建一个类就行!// 修改某个支付方式?只改对应的类!// 老板:再加个云闪付!// 你:淡定新建一个类 😎【代码结构图解】
┌─────────────────────────────────────────────────────────────────┐ │ 上下文 (Context) │ │ PaymentContext │ │ ┌─────────────────────────────────────────┐ │ │ │ setStrategy(PaymentStrategy strategy) │ │ │ │ executePay(BigDecimal amount) │ │ │ │ → strategy.pay(amount) │ │ │ └─────────────────────────────────────────┘ │ └───────────────────────────┬─────────────────────────────────────┘ │ ▼ 持有策略接口 ┌─────────────────────────────────────────────────────────────────┐ │ 策略接口 (Strategy) │ │ PaymentStrategy │ │ ┌─────────────────────────────────────────┐ │ │ │ pay(BigDecimal amount) │ │ │ │ calculateFee(BigDecimal amount) │ │ │ └─────────────────────────────────────────┘ │ └───────────────────────────┬─────────────────────────────────────┘ │ ┌───────────────┼───────────────┐ ▼ ▼ ▼ ┌────────────────┐ ┌────────────────┐ ┌────────────────┐ │ AlipayStrategy │ │ WechatStrategy │ │ BankStrategy │ │ 支付宝策略 │ │ 微信策略 │ │ 银行卡策略 │ │ │ │ │ │ │ │ pay() │ │ pay() │ │ pay() │ │ 0.6%手续费 │ │ 0.5%手续费 │ │ 固定2元 │ └────────────────┘ └────────────────┘ └────────────────┘【核心代码示例 - 支付系统】
1️⃣ 定义策略接口
// 支付策略接口publicinterfacePaymentStrategy{// 支付voidpay(BigDecimalamount);// 计算手续费BigDecimalcalculateFee(BigDecimalamount);// 验证booleanvalidate();}2️⃣ 具体策略实现
🔷 支付宝支付策略
publicclassAlipayStrategyimplementsPaymentStrategy{@Overridepublicvoidpay(BigDecimalamount){System.out.println("【支付宝】支付金额:"+amount+"元");System.out.println("【支付宝】调用支付宝SDK...");System.out.println("【支付宝】正在刷脸...");System.out.println("【支付宝】支付成功!花呗额度-"+amount);}@OverridepublicBigDecimalcalculateFee(BigDecimalamount){// 支付宝手续费 0.6%,马爸爸要恰饭的嘛returnamount.multiply(newBigDecimal("0.006"));}@Overridepublicbooleanvalidate(){System.out.println("【支付宝】验证账户余额...");System.out.println("【支付宝】余额不足,自动切换花呗!");returntrue;}}🟢 微信支付策略
publicclassWechatPayStrategyimplementsPaymentStrategy{@Overridepublicvoidpay(BigDecimalamount){System.out.println("【微信支付】支付金额:"+amount+"元");System.out.println("【微信支付】调用微信SDK...");System.out.println("【微信支付】正在加载小程序...");System.out.println("【微信支付】支付成功!零钱-"+amount);}@OverridepublicBigDecimalcalculateFee(BigDecimalamount){// 微信手续费 0.5%,比支付宝良心一点点returnamount.multiply(newBigDecimal("0.005"));}@Overridepublicbooleanvalidate(){System.out.println("【微信支付】验证微信账户...");System.out.println("【微信支付】检测到你是尊贵的VIP用户!");returntrue;}}🟡 银行卡支付策略
publicclassBankCardStrategyimplementsPaymentStrategy{@Overridepublicvoidpay(BigDecimalamount){System.out.println("【银行卡】支付金额:"+amount+"元");System.out.println("【银行卡】调用银联接口...");System.out.println("【银行卡】正在连接银行服务器...");System.out.println("【银行卡】支付成功!余额-"+amount);System.out.println("【银行卡】短信通知已发送至您的手机");}@OverridepublicBigDecimalcalculateFee(BigDecimalamount){// 银行卡固定手续费 2元,不管你买1块还是1万,都是2块// 买1块钱的东西血亏 😂returnnewBigDecimal("2");}@Overridepublicbooleanvalidate(){System.out.println("【银行卡】验证卡号和密码...");System.out.println("【银行卡】正在发送验证码到138****8888...");System.out.println("【银行卡】验证码输入超时,请重新获取!");System.out.println("【银行卡】开玩笑的,验证通过了~");returntrue;}}3️⃣ 上下文类(使用策略)
// 支付上下文publicclassPaymentContext{privatePaymentStrategystrategy;// 设置策略(可以在构造时或运行时设置)publicvoidsetStrategy(PaymentStrategystrategy){this.strategy=strategy;}// 执行支付publicvoidexecutePay(BigDecimalamount){if(strategy==null){thrownewIllegalStateException("请先设置支付方式");}// 1. 验证if(strategy.validate()){// 2. 计算手续费BigDecimalfee=strategy.calculateFee(amount);BigDecimaltotal=amount.add(fee);System.out.println("\n========== 支付详情 ==========");System.out.println("商品金额:"+amount+"元");System.out.println("手续费:"+fee+"元");System.out.println("应付总额:"+total+"元");System.out.println("==============================\n");// 3. 执行支付strategy.pay(total);}else{System.out.println("支付验证失败!");}}}4️⃣ 客户端使用
publicclassOrderService{publicvoidcheckout(StringpayType,BigDecimalamount){PaymentContextcontext=newPaymentContext();// 根据支付方式选择策略switch(payType){case"alipay":context.setStrategy(newAlipayStrategy());break;case"wechat":context.setStrategy(newWechatPayStrategy());break;case"bank":context.setStrategy(newBankCardStrategy());break;default:thrownewIllegalArgumentException("不支持的支付方式:"+payType);}// 执行支付(不需要知道具体用哪个策略)context.executePay(amount);}}使用示例:
OrderServiceservice=newOrderService();service.checkout("alipay",newBigDecimal("100"));// 支付宝支付service.checkout("wechat",newBigDecimal("100"));// 微信支付service.checkout("bank",newBigDecimal("100"));// 银行卡支付【策略模式的优缺点】
✅ 优点:
| 优点 | 说明 |
|---|---|
| 算法/行为独立 | 易于切换、理解和扩展 |
| 避免使用多重条件判断 | 告别 if-else 地狱 |
| 每个策略独立封装 | 修改不影响其他策略 |
| 符合开闭原则 | 新增策略只需新增类 |
| 老板改需求时 | 你可以淡定地说:“就改一个类” 😏 |
❌ 缺点:
| 缺点 | 说明 |
|---|---|
| 策略类数量增多 | 每个策略一个类 |
| 客户端必须知道所有策略类 | 并自行决定使用哪一个 |
| 策略之间可能会有重复代码 | 可以用组合优化 |
| 类多了,找起来有点费劲 | IDE:你在教我做事? |
【适用场景】
✅ 适合用:
- 系统需要动态地在几种算法中选择一种
- 一个类定义了多种行为,并且这些行为在这个类的操作中以多个条件语句出现
- 需要隐藏复杂的算法/数据结构
- 一个类中的大量代码依赖于某个条件,比如类型
❌ 不适合:
- 策略数量很少(1-2个),没必要搞这么复杂
- 策略之间差异极小,可以合并
【常见应用场景】
- 💰支付方式选择(支付宝/微信/银行卡)
- 🎁促销活动计算(满减/折扣/秒杀)
- 📊排序算法选择(快速排序/归并排序/冒泡排序)
- 📄文件导出格式(PDF/Excel/Word)
- 📱消息发送渠道(短信/邮件/推送)
- 👑会员等级计算(普通/VIP/SVIP)
【使用口诀】
🎯 算法行为多又杂,
🎯 策略模式来帮忙。
🎯 每个算法一个类,
🎯 随意切换真方便!
🎯 告别 if-else 地狱,
🎯 代码清爽不抓狂!
【和工厂模式的区别】
| 对比 | 工厂模式 | 策略模式 |
|---|---|---|
| 关注重点 | 对象的创建 | 行为的封装 |
| 核心目的 | 解耦对象创建 | 解耦算法使用 |
| 使用方式 | factory.create() | strategy.do() |
| 经典组合 | 可以一起用! | 工厂创建策略 |
二、工厂模式 + 策略模式
一句话理解
工厂模式负责"创建策略对象",策略模式负责"执行算法"。
两者结合 = 创建与使用的完美解耦,代码优雅到飞起!
【为什么要组合使用?】
❌ 只用策略模式,客户端代码是这样的:
publicclassOrderService{publicvoidcheckout(StringpayType,BigDecimalamount){PaymentContextcontext=newPaymentContext();// 客户端需要知道所有策略类,还要自己判断用哪个// 每加一种支付方式,这里就要改一次!switch(payType){case"alipay":context.setStrategy(newAlipayStrategy());// 直接 new,耦合!break;case"wechat":context.setStrategy(newWechatPayStrategy());break;case"bank":context.setStrategy(newBankCardStrategy());break;// 老板:再加个云闪付!// 你:又要改客户端代码... 😭}context.executePay(amount);}}✅ 工厂+策略组合,客户端代码变成这样:
publicclassOrderService{publicvoidcheckout(StringpayType,BigDecimalamount){PaymentContextcontext=newPaymentContext();// 一行代码搞定!工厂帮我创建策略!context.setStrategy(PaymentStrategyFactory.getStrategy(payType));context.executePay(amount);}}// 老板:再加个云闪付!// 你:只改工厂,客户端代码不动!😎【组合使用的核心好处】
| 好处 | 说明 |
|---|---|
| 彻底解耦 | 客户端不依赖任何具体策略类,只依赖接口 |
| 开闭原则 | 新增策略只需:1.新建策略类 2.注册到工厂 |
| 代码复用 | 工厂可以全局复用,避免到处 new |
| 易于测试 | 可以 mock 工厂返回的策略,方便单元测试 |
| 配置化 | 策略类型可以写在配置文件里,不用改代码 |
【代码结构图解】
┌─────────────────────────────────────────────────────────────────┐ │ 客户端 (Client) │ │ OrderService │ │ │ │ // 客户端只认识工厂和接口,不认识具体策略! │ │ strategy = PaymentStrategyFactory.getStrategy("alipay") │ │ context.setStrategy(strategy) │ │ context.executePay(amount) │ │ │ └───────────────────────────┬─────────────────────────────────────┘ │ ▼ 工厂创建策略 ┌─────────────────────────────────────────────────────────────────┐ │ 工厂 (PaymentStrategyFactory) │ │ │ │ Map<String, PaymentStrategy> │ │ ├─ "alipay" → new AlipayStrategy() │ │ ├─ "wechat" → new WechatPayStrategy() │ │ ├─ "bank" → new BankCardStrategy() │ │ └─ "union" → new UnionPayStrategy() ← 新增只需加这一行! │ │ │ │ getStrategy(String type) → 返回对应策略 │ │ │ └───────────────────────────┬─────────────────────────────────────┘ │ ▼ 返回策略对象 ┌─────────────────────────────────────────────────────────────────┐ │ 上下文 (PaymentContext) │ │ │ │ setStrategy(PaymentStrategy strategy) │ │ executePay(BigDecimal amount) { │ │ strategy.validate(); │ │ strategy.calculateFee(amount); │ │ strategy.pay(amount); │ │ } │ │ │ └───────────────────────────┬─────────────────────────────────────┘ │ ▼ 调用策略方法 ┌─────────────────────────────────────────────────────────────────┐ │ 具体策略 (Concrete Strategies) │ │ │ │ ┌──────────────────┐ ┌──────────────────┐ ┌──────────────┐ │ │ │ AlipayStrategy │ │ WechatPayStrategy│ │ BankStrategy │ │ │ │ 支付宝策略 │ │ 微信策略 │ │ 银行卡策略 │ │ │ └──────────────────┘ └──────────────────┘ └──────────────┘ │ │ │ └─────────────────────────────────────────────────────────────────┘【工厂 + 策略 代码实现】
1️⃣ 策略工厂类
publicclassPaymentStrategyFactory{// 用一个 Map 缓存所有策略,避免重复创建privatestaticfinalMap<String,PaymentStrategy>STRATEGY_MAP=newHashMap<>();// 静态代码块,初始化所有策略static{STRATEGY_MAP.put("alipay",newAlipayStrategy());STRATEGY_MAP.put("wechat",newWechatPayStrategy());STRATEGY_MAP.put("bank",newBankCardStrategy());// 老板:再加个云闪付!// 你:只加这一行就行!😎// STRATEGY_MAP.put("union", new UnionPayStrategy());}/** * 根据支付类型获取对应策略 * @param payType 支付类型 * @return 支付策略 */publicstaticPaymentStrategygetStrategy(StringpayType){PaymentStrategystrategy=STRATEGY_MAP.get(payType);if(strategy==null){thrownewIllegalArgumentException("不支持的支付方式:"+payType);}returnstrategy;}/** * 获取所有支持的支付方式(方便前端展示) */publicstaticSet<String>getAllPayTypes(){returnSTRATEGY_MAP.keySet();}}2️⃣ 优化后的客户端代码
@ServicepublicclassOrderService{@AutowiredprivatePaymentContextpaymentContext;/** * 结账 - 工厂+策略模式版本 * 客户端代码简洁到令人发指! */publicvoidcheckout(StringpayType,BigDecimalamount){// 一行代码搞定!工厂帮我创建策略!PaymentStrategystrategy=PaymentStrategyFactory.getStrategy(payType);// 设置策略并执行paymentContext.setStrategy(strategy);paymentContext.executePay(amount);}}3️⃣ Spring Boot 实战版本
@ConfigurationpublicclassStrategyConfig{/** * 将策略注册为 Spring Bean,方便管理和扩展 */@BeanpublicMap<String,PaymentStrategy>paymentStrategies(AlipayStrategyalipayStrategy,WechatPayStrategywechatStrategy,BankCardStrategybankStrategy){Map<String,PaymentStrategy>strategies=newHashMap<>();strategies.put("alipay",alipayStrategy);strategies.put("wechat",wechatStrategy);strategies.put("bank",bankStrategy);returnstrategies;}}@ServicepublicclassPaymentService{@AutowiredprivateMap<String,PaymentStrategy>strategies;@AutowiredprivatePaymentContextcontext;publicvoidpay(StringpayType,BigDecimalamount){PaymentStrategystrategy=strategies.get(payType);if(strategy==null){thrownewBusinessException("不支持的支付方式");}context.setStrategy(strategy);context.executePay(amount);}}4️⃣ 对比总结
| 场景 | 纯策略模式 | 工厂+策略模式 |
|---|---|---|
| 新增支付方式 | 改客户端代码 😭 | 只改工厂 😎 |
| 客户端代码 | 又长又臭 | 一行搞定 |
| 耦合度 | 高(直接 new) | 低(工厂创建) |
| 可测试性 | 难 mock | 易 mock |
| 配置化 | 不支持 | 支持 YAML/DB 配置 |
💡温馨提示:策略模式 + 工厂模式是实际项目中的黄金搭档,既能解耦算法,又能解耦对象的创建,强烈推荐在实际项目中使用!
📌写文不易,Bug 更不易。
如果这篇文章对你有帮助,可以搜一搜:空门技术栈
https://mp.weixin.qq.com/s/v4JI6UnfQldz2R9b_GfxGQ
推荐阅读:
写 Java 别只会 new:工厂模式,才是对象界的正规军!
这里分享:
- ✅ Java / Spring AI / 企业级项目实战
- ✅ Docker / RAG知识库 / 微服务踩坑
- ✅ Python、前端、AI应用落地
- ✅ 偶尔分享一些「头发保卫战」经验 😆
一个热爱技术、持续填坑的开发者,
陪你一起少踩坑,少加班,多写优雅代码。