策略模式:定义、结构、实现、与状态模式的区别、优缺点、应用场景
策略模式,说白了就是「把算法或行为封装起来,让它们可以互相替换」。我刚开始接触设计模式时,觉得这玩意儿不就是多态吗?后来在项目中踩过坑才明白——它解决的核心问题,是如何让代码对修改关闭,对扩展开放。
你想想看,如果业务逻辑里有一堆 if-else,每次新增一种策略就要改原来的类,那维护起来得多痛苦?策略模式就是帮你把这些「变化的部分」抽出来,变成一个个独立的策略类。
1. 定义与核心思想
策略模式属于行为型设计模式。它定义了一系列算法,把每个算法封装起来,让它们可以互相替换。算法的变化不会影响使用算法的客户端。
我记得有一次做支付系统,对接了微信、支付宝、银联三种支付方式。一开始用 if-else 硬编码,后来新增一个云闪付,改得我头皮发麻。重构为策略模式后,新增支付方式只需要加一个类,再也不用动原来的代码了。
2. 结构组成
策略模式的结构其实很简单,就三个角色:
- 策略接口(Strategy): 定义所有策略必须实现的方法。比如一个支付接口,里面有个 pay() 方法。
- 具体策略(ConcreteStrategy): 实现策略接口,封装具体的算法或行为。比如微信支付策略、支付宝支付策略。
- 上下文(Context): 持有策略接口的引用,负责调用策略。它不关心具体是哪个策略在干活。
嗯,这里要注意:上下文本身不实现策略,它只是「委托」给策略对象去执行。说白了,上下文就是个调度员。
3. 代码实现
我习惯用支付场景来演示。先看策略接口:
// 策略接口
public interface PaymentStrategy {
void pay(double amount);
}
然后是两个具体策略:
// 具体策略A:微信支付
public class WechatPay implements PaymentStrategy {
@Override
public void pay(double amount) {
System.out.println("使用微信支付:" + amount + "元");
// 实际的微信支付逻辑...
}
}
// 具体策略B:支付宝支付
public class Alipay implements PaymentStrategy {
@Override
public void pay(double amount) {
System.out.println("使用支付宝支付:" + amount + "元");
// 实际的支付宝逻辑...
}
}
接下来是上下文类:
// 上下文
public class PaymentContext {
private PaymentStrategy strategy;
// 可以通过构造器或setter注入策略
public PaymentContext(PaymentStrategy strategy) {
this.strategy = strategy;
}
public void setStrategy(PaymentStrategy strategy) {
this.strategy = strategy;
}
public void executePayment(double amount) {
strategy.pay(amount);
}
}
客户端使用:
public class Client {
public static void main(String[] args) {
PaymentContext context = new PaymentContext(new WechatPay());
context.executePayment(100.0); // 微信支付100元
// 运行时切换策略
context.setStrategy(new Alipay());
context.executePayment(200.0); // 支付宝支付200元
}
}
你看,客户端只需要知道策略接口,根本不用关心具体实现。新增一种支付方式,只需要加一个类,完全符合开闭原则。
4. 策略模式与状态模式的区别
这个问题面试经常问。我简单说下我的理解:
| 对比维度 | 策略模式 | 状态模式 |
|---|---|---|
| 核心意图 | 封装算法,让它们互相替换 | 封装状态,让对象在不同状态下行为不同 |
| 谁决定切换 | 客户端(外部)决定用哪个策略 | 状态对象自身决定下一个状态 |
| 状态数量 | 策略之间是平等的,没有顺序 | 状态之间有明确的转换规则 |
| 典型场景 | 支付方式、排序算法、压缩算法 | 订单状态、工作流、游戏角色状态 |
说白了,策略模式是「我选你干活」,状态模式是「我根据当前状态自动变」。我曾经在项目中把状态模式误用成策略模式,结果状态转换逻辑散得到处都是,后来重构才改回来。
5. 优缺点分析
优点:
- 符合开闭原则,新增策略不需要改原有代码
- 避免大量的 if-else 或 switch-case
- 策略可以复用,同一个策略可以在不同上下文使用
- 便于单元测试,每个策略可以单独测试
缺点:
- 客户端必须了解所有策略的区别,才能选择合适的策略
- 策略类数量会增多,每个策略一个类
- 策略之间如果有公共逻辑,处理起来比较麻烦
6. 应用场景
策略模式在实际项目中非常常见。我列几个典型的:
- 支付系统: 微信、支付宝、银联、云闪付等不同支付方式
- 排序算法: 快速排序、归并排序、冒泡排序等,客户端根据需要选择
- 压缩工具: ZIP、GZIP、RAR 等不同压缩算法
- 促销活动: 满减、折扣、赠品等不同促销策略
- 数据导出: 导出为 Excel、PDF、CSV 等不同格式
你想想看,这些场景都有一个共同点:行为有多种实现方式,而且未来可能还会增加。这时候用策略模式,就是最自然的选择。
7. 核心知识图谱
下面这张图帮你理清策略模式的核心逻辑:
从这张图可以看得很清楚:上下文只依赖策略接口,具体策略之间互不依赖。客户端可以自由选择、切换策略,完全不影响其他部分。
公众号:蓝海资料掘金营,微信deep3321