目录
1. 什么是策略模式
策略模式(Strategy Pattern)是一种行为型设计模式,它定义了一系列算法,并将每个算法封装起来,使它们可以相互替换。策略模式让算法的变化独立于使用算法的客户端。
这种模式特别适合以下场景:
- 需要在运行时动态切换算法的场景
- 有一组类似的算法,只是具体实现不同
- 算法的使用者不需要知道算法的具体实现
- 需要消除一系列的条件语句
2. 策略模式的结构
策略模式主要包含以下三个角色:
- Strategy(策略接口):定义所有支持的算法的公共接口
- ConcreteStrategy(具体策略):实现了Strategy接口的具体算法
- Context(上下文):持有一个Strategy的引用,用于调用具体的算法
3. UML类图
UML类图说明
- Strategy(策略接口)
- 这是策略模式的核心,定义了算法的公共接口
- 通常只包含一个用于执行算法的方法
- 可以包含算法所需的参数
- ConcreteStrategy(具体策略)
- 实现了Strategy接口定义的算法
- 包含算法的具体逻辑
- 可以有多个不同的实现
- Context(上下文)
- 维护一个对Strategy对象的引用
- 负责在运行时设置具体的策略
- 调用策略对象的算法方法
4. 代码实现
让我们通过一个支付方式的例子来实现策略模式:
支付策略示例说明
在电商系统中,通常需要支持多种支付方式(支付宝、微信支付、银行卡等)。这是策略模式的典型应用场景,因为:
- 每种支付方式的具体实现不同
- 需要在运行时根据用户选择切换支付方式
- 支付处理逻辑应该独立于具体的支付方式
完整代码实现
// 支付策略接口
public interface PaymentStrategy {
/**
* 处理支付
* @param amount 支付金额
* @return 支付是否成功
*/
boolean pay(double amount);
}
// 支付宝支付策略
public class AlipayStrategy implements PaymentStrategy {
private String alipayAccount;
public AlipayStrategy(String alipayAccount) {
this.alipayAccount = alipayAccount;
}
@Override
public boolean pay(double amount) {
// 实际项目中这里会调用支付宝SDK
System.out.println("使用支付宝账户" + alipayAccount + "支付" + amount + "元");
return true;
}
}
// 微信支付策略
public class WeChatPayStrategy implements PaymentStrategy {
private String wechatId;
public WeChatPayStrategy(String wechatId) {
this.wechatId = wechatId;
}
@Override
public boolean pay(double amount) {
// 实际项目中这里会调用微信支付SDK
System.out.println("使用微信账户" + wechatId + "支付" + amount + "元");
return true;
}
}
// 银行卡支付策略
public class BankCardStrategy implements PaymentStrategy {
private String cardNumber;
private String cvv;
private String dateOfExpiry;
public BankCardStrategy(String cardNumber, String cvv, String dateOfExpiry) {
this.cardNumber = cardNumber;
this.cvv = cvv;
this.dateOfExpiry = dateOfExpiry;
}
@Override
public boolean pay(double amount) {
// 实际项目中这里会调用银行卡支付接口
System.out.println("使用银行卡" + cardNumber + "支付" + amount + "元");
return true;
}
}
// 支付上下文
public class PaymentContext {
private PaymentStrategy paymentStrategy;
// 设置支付策略
public void setPaymentStrategy(PaymentStrategy strategy) {
this.paymentStrategy = strategy;
}
// 执行支付
public boolean processPayment(double amount) {
if (paymentStrategy == null) {
throw new IllegalStateException("必须设置支付策略");
}
return paymentStrategy.pay(amount);
}
}
// 客户端使用示例
public class Client {
public static void main(String[] args) {
// 创建支付上下文
PaymentContext context = new PaymentContext();
// 模拟用户选择不同的支付方式
double amount = 100.0;
// 使用支付宝支付
context.setPaymentStrategy(new AlipayStrategy("alice@email.com"));
context.processPayment(amount);
// 使用微信支付
context.setPaymentStrategy(new WeChatPayStrategy("wxid_123456"));
context.processPayment(amount);
// 使用银行卡支付
context.setPaymentStrategy(new BankCardStrategy("1234-5678-9012-3456", "123", "12/24"));
context.processPayment(amount);
}
}
代码详细说明
PaymentStrategy(Strategy)
- 定义了支付算法的统一接口
pay()
方法接收支付金额作为参数- 设计为接口而不是抽象类,提供更大的灵活性
具体策略类分析
- AlipayStrategy
- 实现支付宝支付逻辑
- 需要支付宝账户信息
- WeChatPayStrategy
- 实现微信支付逻辑
- 需要微信ID信息
- BankCardStrategy
- 实现银行卡支付逻辑
- 需要完整的银行卡信息
PaymentContext(Context)角色分析
- 持有PaymentStrategy的引用
- 提供设置策略的方法
- 委托具体策略执行支付操作
- 包含基本的空值检查
5. 策略模式 vs if-else
传统if-else方式
public class TraditionalPayment {
public boolean processPayment(String paymentType, double amount, Map<String, String> paymentInfo) {
if ("alipay".equals(paymentType)) {
// 支付宝支付逻辑
String alipayAccount = paymentInfo.get("account");
System.out.println("使用支付宝账户" + alipayAccount + "支付" + amount + "元");
return true;
} else if ("wechat".equals(paymentType)) {
// 微信支付逻辑
String wechatId = paymentInfo.get("wechatId");
System.out.println("使用微信账户" + wechatId + "支付" + amount + "元");
return true;
} else if ("bankcard".equals(paymentType)) {
// 银行卡支付逻辑
String cardNumber = paymentInfo.get("cardNumber");
System.out.println("使用银行卡" + cardNumber + "支付" + amount + "元");
return true;
} else {
throw new IllegalArgumentException("Unsupported payment type");
}
}
}
对比分析
- 代码组织
- if-else:所有逻辑集中在一个方法中,代码臃肿
- 策略模式:每个算法独立封装,结构清晰
- 扩展性
- if-else:添加新支付方式需要修改原有代码
- 策略模式:只需添加新的策略类,无需修改现有代码
- 维护性
- if-else:逻辑耦合,修改一个分支可能影响其他分支
- 策略模式:各个策略相互独立,易于维护
- 测试性
- if-else:需要测试所有分支的组合
- 策略模式:可以独立测试每个策略
6. 常见应用场景
- 支付系统
- 多种支付方式
- 支付渠道的动态选择
- 排序算法
- 不同的排序策略
- 根据数据特征选择最优算法
- 压缩算法
- 不同的压缩方式
- 根据文件类型选择压缩算法
- 验证策略
- 多种验证方式
- 根据安全级别选择验证方式
7. 优缺点分析
优点
- 算法族的封装:每个算法独立封装,易于维护和扩展
- 消除条件语句:避免复杂的if-else结构
- 运行时切换:可以动态改变对象的行为
- 开闭原则:添加新策略无需修改现有代码
缺点
- 策略类数量增加:每个策略都需要一个类,可能导致类数量增多
- 客户端需要了解策略:客户端需要知道所有的策略,以便选择
- 增加了对象数量:每个策略都是一个对象,会占用更多内存
8. 最佳实践建议
- 策略的创建
// 使用工厂模式创建策略
public class PaymentStrategyFactory {
private static Map<String, PaymentStrategy> strategies = new HashMap<>();
static {
strategies.put("alipay", new AlipayStrategy("default@email.com"));
strategies.put("wechat", new WeChatPayStrategy("default_wxid"));
strategies.put("bankcard", new BankCardStrategy("default_card", "123", "12/24"));
}
public static PaymentStrategy getStrategy(String type) {
PaymentStrategy strategy = strategies.get(type);
if (strategy == null) {
throw new IllegalArgumentException("Invalid payment type: " + type);
}
return strategy;
}
}
为什么这样更好?
- 集中管理策略的创建逻辑,避免策略创建逻辑分散
- 客户端代码不需要知道具体策略的构造细节
- 可以轻松实现策略的单例模式或对象池
- 便于添加策略创建的前置检查和后置处理
- 策略的缓存
public class PaymentContext {
private static final Map<String, PaymentStrategy> strategyCache = new ConcurrentHashMap<>();
public PaymentStrategy getStrategy(String type) {
return strategyCache.computeIfAbsent(type, k -> createStrategy(k));
}
private PaymentStrategy createStrategy(String type) {
// 创建策略的逻辑
}
}
为什么这样更好?
- 避免重复创建相同的策略对象,节省内存
- 提高获取策略的性能,特别是策略创建成本较高时
- 使用ConcurrentHashMap保证线程安全
- computeIfAbsent保证原子性,避免并发问题
- 策略的参数化
public interface PaymentStrategy {
boolean pay(PaymentContext context, double amount);
}
public class PaymentContext {
private Map<String, Object> parameters = new HashMap<>();
public void addParameter(String key, Object value) {
parameters.put(key, value);
}
public Object getParameter(String key) {
return parameters.get(key);
}
}
为什么这样更好?
- 避免策略接口参数过多,提高接口的稳定性
- 支持动态添加新参数,不需要修改接口
- 参数可以在运行时动态变化
- 便于添加参数的验证和转换逻辑
- 策略的验证 - 使用模板方法规范流程
public abstract class AbstractPaymentStrategy implements PaymentStrategy {
@Override
public final boolean pay(double amount) {
if (!validate(amount)) {
return false;
}
return doPayment(amount);
}
protected abstract boolean validate(double amount);
protected abstract boolean doPayment(double amount);
}
为什么这样更好?
- **使用模板方法模式规范策略执行流程**
- **强制子类实现必要的验证逻辑**
- **避免重复编写流程控制代码**
- **便于统一添加日志、监控等横切关注点**
总结
策略模式是一种强大的行为型设计模式,它通过将算法族封装在独立的类中,实现了算法的动态切换。相比传统的if-else方式,策略模式提供了更好的代码组织方式和更强的扩展性。
在实际应用中,策略模式常常与其他模式(如工厂模式、单例模式)结合使用,以实现更复杂的功能。选择使用策略模式时,需要权衡类的数量增加和代码维护性之间的关系。
好的设计模式应该解决实际问题,而不是增加不必要的复杂性。在使用策略模式时,应该始终关注它是否真正简化了你的代码结构,是否提高了代码的可维护性和可扩展性。