文章目录
- [0. 个人感悟](#0. 个人感悟)
- [1. 概念](#1. 概念)
- [2. 适配场景](#2. 适配场景)
-
- [2.1 适合的场景](#2.1 适合的场景)
- [2.2 常见场景举例](#2.2 常见场景举例)
- [3. 实现方法](#3. 实现方法)
-
- [3.1 实现思路](#3.1 实现思路)
- [3.2 UML类图](#3.2 UML类图)
- [3.3 代码示例](#3.3 代码示例)
- [4. 优缺点](#4. 优缺点)
-
- [4.1 优点](#4.1 优点)
- [4.2 缺点](#4.2 缺点)
- [5. 源码分析](#5. 源码分析)
-
- [5.1 Java Collections框架中的Comparator](#5.1 Java Collections框架中的Comparator)
0. 个人感悟
- 策略模式是很典型的设计模式,非常能突出编程思想:面向接口编程、隔离变化与不变、封装实现
- 实际使用场景挺多,比如不同的支付策略、运维策略等
- 策略模式和状态模式类图很像,但有着本质区别,使用场景不同
- 当策略较多时,建议结合简单工厂模式,抽取策略工厂,将策略选取逻辑放到工厂,有利于职责单一
1. 概念
英文定义 (《设计模式:可复用面向对象软件的基础》)
Define a family of algorithms, encapsulate each one, and make them interchangealbe. Strategy lets the algorithm vary independently form clients that use it.
中文翻译
定义一系列算法,将每一个算法封装起来,并使它们可以相互替换。策略模式让算法独立于使用它的客户而变化。
理解
- 将算法封装成独立的策略类,而不是将算法硬编码在客户端中
- 客户端可以在运行时灵活选择不同的算法实现
- 策略类实现相同的接口,可以无缝替换
- 消除了大量的条件判断语句,使代码更清晰
- 符合开闭原则,增加新策略无需修改现有代码
2. 适配场景
2.1 适合的场景
- 多种算法实现同一功能:当一个任务可以通过多种算法完成,且这些算法可能在不同场景下需要切换时
- 需要消除条件分支:当代码中存在大量if-else或switch-case语句来选择不同算法时
- 算法独立变化:当算法的实现可能会独立于使用它的客户端而变化时
- 运行时决策:当需要在运行时决定使用哪种算法时
2.2 常见场景举例
- 支付系统:多种支付方式(信用卡、PayPal、微信、支付宝)
- 排序算法:不同排序策略(快速排序、归并排序、堆排序)
- 压缩算法:不同压缩格式(ZIP、RAR、7Z、GZIP)
- 导航系统:不同路径规划策略(最短路径、最少时间、避开高速)
- 验证系统:不同验证方式(邮箱、手机、人脸识别)
- 折扣策略:不同促销活动(满减、折扣、返现)
- 数据导出:不同格式导出(CSV、PDF、Excel、JSON)
3. 实现方法
3.1 实现思路
- 识别系统中可能变化的部分,将其抽象为策略接口
- 为每个具体算法创建实现策略接口的类
- 创建上下文类,持有策略接口的引用
- 在上下文类中提供设置策略的方法
- 客户端根据需要创建具体策略对象并设置给上下文
- 上下文通过策略接口调用具体算法,而不知道具体实现细节
3.2 UML类图

角色说明:
- Context(上下文):持有一个Strategy对象的引用,并通过该接口调用具体算法
- Strategy(策略接口):定义所有支持的算法的公共接口
- ConcreteStrategy(具体策略):实现Strategy接口的具体算法类
3.3 代码示例
背景
已购物支付为例
- 简化业务逻辑,支付策略可以是支付宝、微信,支持切换
策略接口和实现类
java
public interface PaymentStrategy {
/**
* @return designpattern.strategy.PayType 支付类型
* @description 获取支付类型,策略key
* @author bigHao
* @date 2026/1/28
**/
PayType getPayType();
/**
* @param amount 金额
* @description 支付
* @author bigHao
* @date 2026/1/28
**/
void pay(double amount);
}
public class PayPalStrategy implements PaymentStrategy {
private String email;
public PayPalStrategy(String email) {
this.email = email;
}
@Override
public PayType getPayType() {
return PayType.PAY_PAL;
}
@Override
public void pay(double amount) {
System.out.println(STR."pay \{amount} using PayPal with email \{email}");
}
}
public class WeChatPayStrategy implements PaymentStrategy {
private String weChatId;
public WeChatPayStrategy(String weChatId) {
this.weChatId = weChatId;
}
@Override
public PayType getPayType() {
return PayType.WECHAT_PAY;
}
@Override
public void pay(double amount) {
System.out.println(STR."pay \{amount} using WeChatPay with id \{weChatId}");
}
}
策略工厂
java
public class PayStrategyFactory {
public static Map<PayType, PaymentStrategy> map = new HashMap<PayType, PaymentStrategy>();
static {
PaymentStrategy aliPay = new PayPalStrategy("11111@ali.com");
PaymentStrategy weChatPay = new WeChatPayStrategy("weChatId001");
map.put(aliPay.getPayType(), aliPay);
map.put(weChatPay.getPayType(), weChatPay);
}
/**
* @param payType
* @return designpattern.strategy.PaymentStrategy 支付策略
* @description 获取策略
* @author bigHao
* @date 2026/1/28
**/
public static PaymentStrategy getPaymentStrategy(PayType payType) {
return map.get(payType);
}
}
上下文
java
public class ShoppingCart {
private double amount;
private PaymentStrategy strategy;
/**
* @description 结账
* @author bigHao
* @date 2026/1/28
**/
public void checkOut() {
strategy.pay(amount);
}
public double getAmount() {
return amount;
}
public void setAmount(double amount) {
this.amount = amount;
}
public PaymentStrategy getStrategy() {
return strategy;
}
public void setStrategy(PaymentStrategy strategy) {
this.strategy = strategy;
}
}
辅助类
java
public enum PayType {
PAY_PAL, // 支付宝
WECHAT_PAY // 微信
}
测试
java
public class Client {
static void main() {
// 初始化
ShoppingCart cart = new ShoppingCart();
cart.setAmount(100);
// 支付宝
cart.setStrategy(PayStrategyFactory.getPaymentStrategy(PayType.PAY_PAL));
cart.checkOut();
// 切换到微信
cart.setStrategy(PayStrategyFactory.getPaymentStrategy(PayType.WECHAT_PAY));
cart.checkOut();
}
}
输出
pay 100.0 using PayPal with email 11111@ali.com
pay 100.0 using WeChatPay with id weChatId001
4. 优缺点
4.1 优点
-
高内聚低耦合
- 算法实现与使用分离,提高了内聚性
- 上下文与具体策略解耦,降低了耦合度
-
开闭原则
- 易于扩展新策略,无需修改现有代码
- 支持在不修改上下文的情况下增加新算法
-
可读性
- 消除了复杂的条件判断语句
- 每个策略类职责单一,代码清晰
-
可维护性
- 算法变化独立,修改一个策略不影响其他
- 便于单元测试,每个策略可单独测试
-
复用性
- 策略类可以在不同的上下文环境中复用
- 避免了代码重复
4.2 缺点
-
策略类数量增加
- 每个算法一个类,可能导致类数量膨胀
- 需要权衡策略划分的粒度
-
客户端必须了解策略差异
- 客户端需要知道不同策略的区别和适用场景
- 增加了客户端的复杂性
-
对象创建开销
- 频繁创建和销毁策略对象可能带来性能开销
- 可考虑使用对象池或享元模式优化
-
策略间通信困难
- 策略间相互独立,难以共享数据
- 需要额外的通信机制
5. 源码分析
5.1 Java Collections框架中的Comparator
代码流程
java
// java.util.Comparator接口就是策略模式的典型应用
public interface Comparator<T> {
int compare(T o1, T o2);
}
// 具体策略:字符串长度比较器
public class StringLengthComparator implements Comparator<String> {
@Override
public int compare(String s1, String s2) {
return Integer.compare(s1.length(), s2.length());
}
}
// 上下文:Collections.sort()方法
public static <T> void sort(List<T> list, Comparator<? super T> c) {
list.sort(c);
}
// 使用示例
List<String> names = Arrays.asList("Alice", "Bob", "Charlie");
Collections.sort(names, new StringLengthComparator());
角色分析*
- Strategy接口:Comparator
- 具体策略:各种实现了Comparator的类,如StringLengthComparator
- Context:Collections.sort()方法或List.sort()方法
- 客户端:调用排序方法的代码
参考: