策略模式(Strategy Pattern)
策略模式是一种行为型设计模式,它通过将算法或行为封装成独立的策略对象,使它们可以相互替换,从而实现算法的动态切换,同时避免使用多重条件判断语句。这种模式在需要灵活选择不同处理方式的场景中非常有用。
一、定义
官方定义: Define a family of algorithms, encapsulate each one, and make them interchangeable. Strategy lets the algorithm vary independently from clients that use it. (定义一系列算法,将每个算法都封装起来,并且使它们之间可以互换。策略模式使算法可以独立于使用它的客户端而变化。)
通俗理解: 策略模式就像我们日常生活中的 "锦囊妙计"—— 针对同一个问题(如出行),有多种解决方案(步行、骑车、开车、乘公交),我们可以根据实际情况(距离、天气、时间)选择合适的策略,并且可以随时切换。
二、意图
策略模式的核心目标是解决以下问题:
- 消除多重条件判断:避免使用
if-else或switch语句来选择不同的算法,提高代码可维护性; - 算法的封装与复用:将不同算法封装成独立组件,便于单独维护和复用;
- 动态切换算法:允许在运行时根据需求灵活切换算法,无需修改客户端代码;
- 开放 - 封闭原则:新增算法时无需修改现有代码,只需添加新的策略类。
三、结构
策略模式包含 3 个核心角色:
| 角色名称 | 核心职责 |
|---|---|
| 抽象策略(Strategy) | 定义所有支持的算法的公共接口,通常是一个接口或抽象类,声明算法的执行方法。 |
| 具体策略(ConcreteStrategy) | 实现抽象策略定义的接口,包含具体的算法逻辑。 |
| 环境类(Context) | 持有一个策略对象的引用,负责策略的切换和调用,是客户端与策略之间的中间层。 |
四、类图(Mermaid 版)

以 "支付系统" 为场景,展示策略模式的结构:
classDiagram
direction TB
%% 1. 抽象策略:支付策略接口
class PaymentStrategy {
<<interface>>
+ pay(amount: double): boolean // 支付方法
}
%% 2. 具体策略:各种支付方式
class AliPayStrategy {
+ pay(amount: double): boolean
}
class WechatPayStrategy {
+ pay(amount: double): boolean
}
class CreditCardStrategy {
+ pay(amount: double): boolean
}
%% 3. 环境类:支付上下文
class PaymentContext {
- strategy: PaymentStrategy // 持有策略引用
+ setStrategy(strategy: PaymentStrategy): void // 设置策略
+ executePayment(amount: double): boolean // 执行支付
}
%% 关系
PaymentContext "1" --> "使用" PaymentStrategy : 依赖 >
AliPayStrategy ..|> PaymentStrategy : 实现
WechatPayStrategy ..|> PaymentStrategy : 实现
CreditCardStrategy ..|> PaymentStrategy : 实现
五、时序图(Mermaid 版)
以 "用户选择支付宝支付" 为场景,展示策略模式的交互流程:
sequenceDiagram
participant Client as 客户端(用户)
participant Context as 环境类(PaymentContext)
participant AliPay as 具体策略(AliPayStrategy)
%% 1. 初始化
Client->>AliPay: 1. 创建支付宝策略对象
Client->>Context: 2. 创建支付上下文
Client->>Context: 3. setStrategy(aliPay) // 设置策略
%% 2. 执行支付
Client->>Context: 4. executePayment(99.0) // 发起支付请求
Context->>AliPay: 5. pay(99.0) // 调用策略的支付方法
AliPay-->>Context: 6. 返回支付结果(成功/失败)
Context-->>Client: 7. 返回支付结果
六、模式分析
6.1 核心逻辑:封装与委托
策略模式的关键在于将算法的定义与使用分离:
- 算法的具体实现封装在具体策略类中;
- 环境类持有策略的引用,并将具体的算法调用委托给策略对象;
- 客户端通过环境类间接使用策略,无需直接与具体策略交互。
这种设计使得:
- 算法可以独立于客户端变化;
- 新增或替换算法只需操作策略对象,无需修改客户端或环境类代码;
- 避免了使用多重条件判断语句,提高代码可读性。
6.2 与状态模式的区别
策略模式常与状态模式混淆,两者都使用了封装和委托的思想,但意图不同:
| 对比维度 | 策略模式(Strategy) | 状态模式(State) |
|---|---|---|
| 核心意图 | 封装不同的算法,允许客户端选择和切换 | 封装对象的不同状态及其行为,状态由对象自身决定 |
| 切换方式 | 通常由客户端主动切换策略 | 状态切换通常由状态对象或环境类内部决定 |
| 策略 / 状态关系 | 策略之间通常无依赖关系 | 状态之间可能存在流转关系(如待支付→已支付) |
| 典型场景 | 支付方式选择、排序算法选择 | 订单状态管理、生命周期管理 |
七、优点
- 消除条件判断:用多态替代
if-else或switch语句,使代码更清晰、更易维护; - 增强扩展性:新增算法只需实现策略接口,无需修改现有代码,符合开放 - 封闭原则;
- 提高复用性:策略对象可以在不同场景中复用;
- 便于测试:每个策略都是独立的类,可以单独进行单元测试;
- 动态切换:允许在运行时根据需求灵活切换算法。
八、缺点
- 增加类数量:每个算法都需要对应一个策略类,可能导致系统中类的数量增加;
- 客户端需了解策略:客户端必须知道所有策略的存在,并理解它们的区别,才能选择合适的策略;
- 策略通信成本:如果策略需要环境类的大量信息,可能需要通过参数传递,增加通信成本;
- 状态维护问题:策略模式不适合需要维护状态的场景,此时状态模式更合适。
九、适用环境
当系统满足以下条件时,适合使用策略模式:
- 系统中存在多种算法,且需要根据不同场景选择使用;
- 需要动态切换算法,如根据用户设置或运行时条件改变处理方式;
- 算法的实现细节需要隐藏,客户端无需知道具体实现;
- 代码中存在复杂的条件判断,且这些判断用于选择不同的处理方式。
典型应用场景:
- 支付系统(支付宝、微信支付、信用卡等);
- 排序算法(冒泡排序、快速排序、归并排序等);
- 折扣计算(会员折扣、节日折扣、促销折扣等);
- 日志记录(控制台日志、文件日志、数据库日志等);
- 路由规划(最短路径、最快路径、最经济路径等)。
十、模式扩展
10.1 策略工厂
结合工厂模式,创建策略工厂类来管理策略的创建,降低客户端与具体策略的耦合:
public class PaymentStrategyFactory {
// 根据支付类型创建对应的策略
public static PaymentStrategy createStrategy(String type) {
switch (type) {
case "alipay":
return new AliPayStrategy();
case "wechat":
return new WechatPayStrategy();
case "creditcard":
return new CreditCardStrategy();
default:
throw new IllegalArgumentException("不支持的支付方式");
}
}
}
客户端使用:
// 无需直接创建策略对象,通过工厂获取
PaymentStrategy strategy = PaymentStrategyFactory.createStrategy("alipay");
context.setStrategy(strategy);
10.2 带缓存的策略
对于创建成本较高的策略,可以添加缓存机制,避免重复创建:
public class CachedPaymentStrategyFactory {
private static final Map<String, PaymentStrategy> CACHE = new HashMap<>();
public static PaymentStrategy getStrategy(String type) {
// 先从缓存获取,不存在则创建并缓存
return CACHE.computeIfAbsent(type, key -> {
switch (key) {
case "alipay":
return new AliPayStrategy();
case "wechat":
return new WechatPayStrategy();
default:
throw new IllegalArgumentException("不支持的支付方式");
}
});
}
}
10.3 策略链
将多个策略组合成链条,依次执行,适用于需要多步处理的场景:
public class StrategyChain {
private List<PaymentStrategy> strategies = new ArrayList<>();
// 添加策略到链条
public void addStrategy(PaymentStrategy strategy) {
strategies.add(strategy);
}
// 依次执行所有策略,直到成功
public boolean executeChain(double amount) {
for (PaymentStrategy strategy : strategies) {
if (strategy.pay(amount)) {
return true;
}
}
return false;
}
}
十一、模式应用
策略模式在软件开发中应用广泛,典型场景包括:
11.1 Java 标准库
java.util.Comparator:比较器接口,不同的比较算法实现了该接口,可用于集合排序;java.util.concurrent.ThreadPoolExecutor:线程池的拒绝策略(RejectedExecutionHandler)使用了策略模式;java.io.FileFilter和java.io.FilenameFilter:文件过滤策略接口。
11.2 框架应用
- Spring Framework:资源访问策略(
Resource接口)、事务管理策略等; - Android:动画插值器(
Interpolator)、布局管理器(LayoutManager)等; - 日志框架:不同的日志输出策略(控制台、文件、数据库)。
11.3 业务场景
- 电商系统:不同的促销策略(满减、折扣、赠品);
- 支付系统:不同的支付渠道和支付方式;
- 导航软件:不同的路线规划策略;
- 游戏开发:不同的 AI 行为策略。
十二、Android 中的应用
Android 框架和开发中,策略模式的应用非常广泛:
12.1 动画插值器(Interpolator)
Android 动画系统使用策略模式定义不同的动画插值策略:
- 抽象策略:
Interpolator接口 - 具体策略:
AccelerateInterpolator、DecelerateInterpolator、LinearInterpolator等 - 环境类:
Animation类持有Interpolator引用
// 使用不同的插值策略
Animation animation = new TranslateAnimation(0, 100, 0, 0);
// 设置加速插值策略
animation.setInterpolator(new AccelerateInterpolator());
// 或者设置减速插值策略
// animation.setInterpolator(new DecelerateInterpolator());
animation.setDuration(1000);
view.startAnimation(animation);
12.2 布局管理器(LayoutManager)
RecyclerView 使用策略模式提供不同的布局策略:
- 抽象策略:
LayoutManager抽象类 - 具体策略:
LinearLayoutManager、GridLayoutManager、StaggeredGridLayoutManager - 环境类:
RecyclerView持有LayoutManager引用
RecyclerView recyclerView = findViewById(R.id.recycler_view);
// 设置线性布局策略
recyclerView.setLayoutManager(new LinearLayoutManager(this));
// 或者设置网格布局策略
// recyclerView.setLayoutManager(new GridLayoutManager(this, 2));
12.3 权限请求策略
在处理 Android 权限请求时,可以使用策略模式定义不同的权限处理策略:
// 抽象策略
public interface PermissionStrategy {
boolean requestPermission(Activity activity, String permission);
}
// 具体策略:简单请求策略
public class SimplePermissionStrategy implements PermissionStrategy {
@Override
public boolean requestPermission(Activity activity, String permission) {
ActivityCompat.requestPermissions(activity, new String[]{permission}, 100);
return true;
}
}
// 具体策略:带解释的请求策略
public class ExplainedPermissionStrategy implements PermissionStrategy {
@Override
public boolean requestPermission(Activity activity, String permission) {
if (ActivityCompat.shouldShowRequestPermissionRationale(activity, permission)) {
// 显示权限解释
showPermissionExplanation(activity);
}
ActivityCompat.requestPermissions(activity, new String[]{permission}, 100);
return true;
}
private void showPermissionExplanation(Activity activity) {
// 显示解释对话框
}
}
十三、代码实现(Java 版)
以 "电商支付系统" 为场景,完整实现策略模式:
13.1 步骤 1:定义抽象策略接口
/**
* 抽象策略:支付策略接口
*/
public interface PaymentStrategy {
/**
* 执行支付
* @param amount 支付金额
* @return 支付是否成功
*/
boolean pay(double amount);
/**
* 获取支付方式名称
* @return 支付方式名称
*/
String getPaymentName();
}
13.2 步骤 2:实现具体策略类
/**
* 具体策略:支付宝支付
*/
public class AliPayStrategy implements PaymentStrategy {
private String account;
private String password;
public AliPayStrategy(String account, String password) {
this.account = account;
this.password = password;
}
@Override
public boolean pay(double amount) {
System.out.println("=== 支付宝支付 ===");
System.out.println("验证账号密码...");
// 模拟支付过程
System.out.println("从支付宝账号 " + account + " 支付 " + amount + " 元");
// 模拟支付成功
return true;
}
@Override
public String getPaymentName() {
return "支付宝";
}
}
/**
* 具体策略:信用卡支付
*/
public class CreditCardStrategy implements PaymentStrategy {
private String cardNumber;
private String name;
private String cvv;
private String expiryDate;
public CreditCardStrategy(String cardNumber, String name, String cvv, String expiryDate) {
this.cardNumber = cardNumber;
this.name = name;
this.cvv = cvv;
this.expiryDate = expiryDate;
}
@Override
public boolean pay(double amount) {
System.out.println("=== 信用卡支付 ===");
System.out.println("验证信用卡信息...");
// 模拟支付过程
System.out.println("使用信用卡 " + maskCardNumber(cardNumber) + " 支付 " + amount + " 元");
// 模拟支付成功
return true;
}
// 隐藏卡号中间部分
private String maskCardNumber(String cardNumber) {
if (cardNumber.length() <= 4) return cardNumber;
return cardNumber.substring(0, 4) + " **** **** " + cardNumber.substring(cardNumber.length() - 4);
}
@Override
public String getPaymentName() {
return "信用卡支付";
}
}
/**
* 具体策略:微信支付
*/
public class WechatPayStrategy implements PaymentStrategy {
private String openId;
public WechatPayStrategy(String openId) {
this.openId = openId;
}
@Override
public boolean pay(double amount) {
System.out.println("=== 微信支付 ===");
System.out.println("验证OpenID...");
// 模拟支付过程
System.out.println("从微信账号 " + openId + " 支付 " + amount + " 元");
// 模拟支付成功
return true;
}
@Override
public String getPaymentName() {
return "微信支付";
}
}
13.3 步骤 3:实现环境类
/**
* 环境类:支付上下文
*/
public class PaymentContext {
// 持有支付策略引用
private PaymentStrategy paymentStrategy;
// 构造方法设置初始策略
public PaymentContext(PaymentStrategy paymentStrategy) {
this.paymentStrategy = paymentStrategy;
}
// 切换支付策略
public void setPaymentStrategy(PaymentStrategy paymentStrategy) {
this.paymentStrategy = paymentStrategy;
System.out.println("已切换到" + paymentStrategy.getPaymentName());
}
// 执行支付
public boolean pay(double amount) {
if (paymentStrategy == null) {
System.err.println("未设置支付方式");
return false;
}
System.out.println("准备进行支付,金额:" + amount + "元");
return paymentStrategy.pay(amount);
}
// 获取当前支付方式
public String getCurrentPaymentName() {
return paymentStrategy != null ? paymentStrategy.getPaymentName() : "未设置";
}
}
13.4 步骤 4:客户端测试
/**
* 客户端:测试支付策略模式
*/
public class PaymentTest {
public static void main(String[] args) {
// 1. 创建不同的支付策略
PaymentStrategy aliPay = new AliPayStrategy("user@example.com", "password123");
PaymentStrategy wechatPay = new WechatPayStrategy("o6_bmjrPTlm6_2sgVt7hMZOPfL2M");
PaymentStrategy creditCard = new CreditCardStrategy(
"6222021234567890123", "张三", "123", "12/25");
// 2. 创建支付上下文,初始使用支付宝
PaymentContext paymentContext = new PaymentContext(aliPay);
// 3. 使用支付宝支付
System.out.println("=== 第一次支付 ===");
boolean success = paymentContext.pay(99.99);
System.out.println("支付" + (success ? "成功" : "失败"));
// 4. 切换到微信支付并支付
System.out.println("\n=== 第二次支付 ===");
paymentContext.setPaymentStrategy(wechatPay);
success = paymentContext.pay(199.50);
System.out.println("支付" + (success ? "成功" : "失败"));
// 5. 切换到信用卡支付并支付
System.out.println("\n=== 第三次支付 ===");
paymentContext.setPaymentStrategy(creditCard);
success = paymentContext.pay(599.00);
System.out.println("支付" + (success ? "成功" : "失败"));
}
}
13.5 运行结果
=== 第一次支付 ===
准备进行支付,金额:99.99元
=== 支付宝支付 ===
验证账号密码...
从支付宝账号 user@example.com 支付 99.99 元
支付成功
=== 第二次支付 ===
已切换到微信支付
准备进行支付,金额:199.5元
=== 微信支付 ===
验证OpenID...
从微信账号 o6_bmjrPTlm6_2sgVt7hMZOPfL2M 支付 199.5 元
支付成功
=== 第三次支付 ===
已切换到信用卡支付
准备进行支付,金额:599.0元
=== 信用卡支付 ===
验证信用卡信息...
使用信用卡 6222 **** **** 0123 支付 599.0 元
支付成功
十四、总结
策略模式通过将算法封装成独立的策略对象,实现了算法的灵活切换和复用,是处理多种相似算法场景的优秀解决方案。
- 核心价值:
- 用多态替代条件判断,使代码更清晰、更易维护;
- 实现算法的动态切换,提高系统的灵活性;
- 符合开放 - 封闭原则,便于扩展新算法;
- 分离算法的定义与使用,降低耦合度。
- 使用建议:
- 当系统中存在 3 个以上相似算法且可能扩展时,优先考虑策略模式;
- 结合工厂模式使用,降低客户端与具体策略的耦合;
- 对于简单场景(仅 2-3 种固定算法),不必过度设计使用策略模式;
- 在 Android 开发中,充分利用系统已有的策略模式实现(如 Interpolator、LayoutManager)。
- 局限性:
- 增加了类的数量,可能提高系统的复杂度;
- 客户端需要了解所有策略才能选择合适的策略;
- 不适合处理依赖状态的算法,此时状态模式可能更合适。
总之,策略模式是一种简单而强大的设计模式,它通过封装变化点,使系统更加灵活、可扩展和可维护,是每个开发者都应该掌握的设计模式之一