策略模式简介及应用场景
关于策略模式在编码过程中的应用,这是一篇跟AI对话得出的学习文章,欢迎交流~
策略模式简介及应用场景:☀️☀️☀️
1. 策略模式(Strategy Pattern)核心解读
策略模式是行为型设计模式的核心之一,定义为:
定义一系列算法,把它们一个个封装起来,并且使它们可互相替换。此模式让算法的变化独立于使用算法的客户。
1.1 通俗理解
把“完成同一任务的不同方法”(比如支付可选择微信、支付宝)抽离为独立的“策略类”,主逻辑(支付流程)只需调用统一接口,切换方法时无需修改主逻辑。
1.2 核心角色(3个)
| 角色 | 作用 |
|---|---|
| 环境类(Context) | 持有策略对象引用,提供统一调用入口,不负责选择具体策略(也可负责) |
| 抽象策略(Strategy) | 定义所有具体策略必须实现的接口/抽象类(如支付的 pay() 方法) |
| 具体策略(ConcreteStrategy) | 实现抽象策略,封装具体算法(如微信支付、支付宝支付的逻辑) |
1.3 核心优势
- 开闭原则:新增策略无需修改原有代码,仅需新增类;
- 消除冗余 if-else:避免主逻辑中大量条件分支的臃肿代码;
- 代码复用+可测试:每个策略独立封装,可单独测试、复用;
- 动态切换:运行时可根据条件切换策略(如用户选择支付方式后自动匹配)。
2. 策略模式在Java中的典型示例(支付场景)
以“支付方式选择”为例,对比不用策略模式和用策略模式的实现。
2.1 反例:不用策略模式(臃肿if-else)
▼text复制代码// 主逻辑耦合所有支付方式,新增/修改需改代码 public class PaymentService { public void pay(String payType, BigDecimal amount) { if ("WECHAT".equals(payType)) { System.out.println("微信支付:" + amount + "元"); // 微信支付的SDK调用、签名等逻辑(数百行) } else if ("ALIPAY".equals(payType)) { System.out.println("支付宝支付:" + amount + "元"); // 支付宝支付的逻辑(数百行) } else if ("BANK".equals(payType)) { System.out.println("银行卡支付:" + amount + "元"); } else { throw new IllegalArgumentException("不支持的支付方式"); } } } // 调用方 public class Client { public static void main(String[] args) { PaymentService service = new PaymentService(); service.pay("WECHAT", new BigDecimal("100")); } }
问题:
- 新增支付方式需修改核心方法,违反开闭原则;
- 代码臃肿,维护成本高;
- 支付逻辑无法单独测试、复用。
2.2 正例:用策略模式重构(大厂标准写法)
步骤1:定义抽象策略(支付接口)
▼text复制代码// 所有支付方式的统一接口 public interface PaymentStrategy { void pay(BigDecimal amount); // 支付方法 String getPayType(); // 获取支付类型(用于匹配) }
步骤2:实现具体策略(各支付方式)
▼text复制代码// 微信支付策略 public class WechatPayment implements PaymentStrategy { @Override public void pay(BigDecimal amount) { System.out.println("【微信支付】发起支付,金额:" + amount + "元"); // 微信SDK调用、签名等逻辑 } @Override public String getPayType() { return "WECHAT"; } } // 支付宝支付策略 public class AlipayPayment implements PaymentStrategy { @Override public void pay(BigDecimal amount) { System.out.println("【支付宝支付】发起支付,金额:" + amount + "元"); // 支付宝SDK调用、验签等逻辑 } @Override public String getPayType() { return "ALIPAY"; } } // 银行卡支付策略 public class BankPayment implements PaymentStrategy { @Override public void pay(BigDecimal amount) { System.out.println("【银行卡支付】发起支付,金额:" + amount + "元"); // 银行接口调用、身份验证等逻辑 } @Override public String getPayType() { return "BANK"; } }
步骤3:定义环境类(统一入口)
▼text复制代码// 封装策略的统一调用入口 public class PaymentContext { // 策略容器:缓存所有支付策略 private static final Map<String, PaymentStrategy> STRATEGY_MAP = new HashMap<>(); // 静态初始化策略 static { STRATEGY_MAP.put(new WechatPayment().getPayType(), new WechatPayment()); STRATEGY_MAP.put(new AlipayPayment().getPayType(), new AlipayPayment()); STRATEGY_MAP.put(new BankPayment().getPayType(), new BankPayment()); } // 外部统一调用方法 public void pay(String payType, BigDecimal amount) { PaymentStrategy strategy = STRATEGY_MAP.get(payType); if (strategy == null) { throw new IllegalArgumentException("不支持的支付方式:" + payType); } strategy.pay(amount); } // 动态添加新策略 public void addStrategy(PaymentStrategy strategy) { STRATEGY_MAP.put(strategy.getPayType(), strategy); } }
步骤4:调用方使用(极简)
▼text复制代码public class Client { public static void main(String[] args) { PaymentContext context = new PaymentContext(); context.pay("WECHAT", new BigDecimal("100")); // 微信支付 context.pay("ALIPAY", new BigDecimal("200")); // 支付宝支付 // 新增策略(无需修改原有代码) // context.addStrategy(new UnionPayPayment()); // context.pay("UNION", new BigDecimal("300")); } }
输出结果:
▼text复制代码【微信支付】发起支付,金额:100元 【支付宝支付】发起支付,金额:200元
2.3 Spring环境下的进阶写法(大厂实战)
结合注解+自动注入,无需手动维护策略容器:
▼text复制代码// 1. 定义策略注解 @Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) public @interface PayStrategy { String value(); // 支付类型 } // 2. 具体策略添加注解+交给Spring管理 @PayStrategy("WECHAT") @Component public class WechatPayment implements PaymentStrategy { /* 实现方法 */ } @PayStrategy("ALIPAY") @Component public class AlipayPayment implements PaymentStrategy { /* 实现方法 */ } // 3. 环境类自动加载策略 @Component public class PaymentContext { private final Map<String, PaymentStrategy> strategyMap; // Spring自动注入所有PaymentStrategy类型的Bean public PaymentContext(List<PaymentStrategy> strategies) { strategyMap = new HashMap<>(); for (PaymentStrategy strategy : strategies) { String payType = strategy.getClass().getAnnotation(PayStrategy.class).value(); strategyMap.put(payType, strategy); } } // 支付方法(同上) public void pay(String payType, BigDecimal amount) { /* 逻辑同上 */ } } // 4. 业务层调用 @Service public class OrderService { @Autowired private PaymentContext paymentContext; public void createOrder(String payType, BigDecimal amount) { // 订单逻辑... paymentContext.pay(payType, amount); } }
3. 策略模式的典型应用场景(大厂高频)
除支付场景外,策略模式在大厂项目中的核心应用:
3.1 业务规则动态切换
- 场景:电商优惠策略(满减、折扣、优惠券)、物流配送策略(顺丰、京东);
- 实现:每种规则封装为策略类,下单时根据订单信息动态匹配。
3.2 算法/接口适配
- 场景:消息推送(短信、钉钉、企业微信)、OSS存储(阿里云、腾讯云);
- 实现:每种推送/存储方式封装为策略,核心逻辑通过统一接口调用。
3.3 框架内置的策略模式
大厂常用框架大量使用策略模式:
- JDK:
Comparator(排序策略)、ThreadPoolExecutor的拒绝策略;
▼text复制代码// Comparator的策略模式应用 List<Integer> list = Arrays.asList(3,1,2); list.sort(Comparator.naturalOrder()); // 升序策略 list.sort(Comparator.reverseOrder()); // 降序策略
- Spring:
Resource(资源加载策略)、HandlerMapping(请求映射策略)。
4. 大厂为什么重视设计模式?
很多新手认为设计模式是“花架子”,但大厂对其重视程度极高,核心原因:
4.1 解决大规模代码的维护性问题
大厂项目代码量可达百万行,人员流动频繁:
- 无设计模式:代码是“面条式”if-else,新人接手需逐行读代码,改一行崩一片;
- 有设计模式:代码遵循统一规范(如策略模式的“接口+实现”),新人快速理解,维护成本降低80%。
4.2 支撑高扩展的业务需求
大厂业务迭代极快(如电商每年新增N种支付方式):
- 无设计模式:新增功能需修改核心代码,风险高;
- 有设计模式:新增策略仅需加新类,符合“开闭原则”,上线风险几乎为0。
4.3 实现代码复用+标准化
大厂强调“不重复造轮子”:
- 策略模式将通用逻辑封装为独立类,可在多模块复用;
- 设计模式是“程序员的通用语言”,说“这里用策略模式”,团队全员理解代码结构,沟通成本降低。
4.4 适配高并发/高可用架构
策略模式的“解耦”特性是高并发架构的基础:
- 支付场景:可按支付类型路由到不同线程池/服务器,实现分流;
- 存储场景:可按数据量切换存储介质(内存/磁盘/OSS),提升性能。
5. 总结
- 策略模式核心:封装算法为独立策略,解耦“使用逻辑”与“具体实现”;
- 典型应用:支付、优惠、推送、存储适配等需动态切换逻辑的场景;
- 大厂价值:维护性(易读易改)、扩展性(新增功能不碰旧代码)、复用性(策略类可复用);
- 避坑点:若策略少于2个且永不扩展,无需使用(避免过度设计)。
评论
问答助学
相关内容
0个评论
全部评论
点击登录,快来和大家讨论吧~
表情
图片
暂无评论
作者分享
工厂方法模式简介及应用场景
3
Spring 源码入门篇
4
入职dayone 刚开始还庆幸这家还好是纯springboot那一套框架开发,
但是进来发现整个开发部就四个人,而且目前这个项目完全是由实习生自己开发的,而且是口头给需求,感觉有点小压力,
毕竟之前没实习过,基本没人带,现在就只能靠另外一个实习的哥们帮忙带一下(他在里面干了三四个月好像也快离开了)
而且今天给了一个小需求,然后要我们自己设计新的表😂 目前想法就是先顶住压力干三个月 后面再找找机会
或者等明年春招,这个思路可以嘛?
还有 问一下已经有过实习经历的友友,有没有建议给到我刚入职的萌新,
像给我一个需求 ,我是先去捋一下思路,需要设计表,哪些字段,还有返回给前端什么数据这些 ,是不是得先想好啊,
项目负责人都没告诉我,就是直接口头给需求 然后我们开发就行😭
现在脑子懵,希望有经验的友友给点建议,平时拿到一个需求是怎么开发的呢
3
用宝塔面板部署的项目,现在报连接不上redis 是什么原因呢?我本身项目代码是没问题的 在本地能正常连接,但是怎么连不上宝塔上面下的reids呢?之前还可以 然后后面项目线上报错我就重新删了再搞 结果就报连接不是redis了,配置密码也没问题呀。有大佬有遇到这种问题嘛,求助!
2
#云图库扩展点 #AI上传优化为消息队列异步执行
有大佬已经完成了这个拓展点了吗,求助!!!
消息队列是这两天看Bi项目的文档笔记现学的。
然后拉bi项目的源码看。搞了一个早上,思路很乱,不清楚生产者跟消费者具体要传什么message,晕了 先吃个饭 下午再整理一下思路,希望有大佬能指点一下😭
4
