1、什么是策略模式?

策略模式(Strategy Pattern)是一种行为型设计模式,它定义了一系列算法,并将每个算法封装起来,使它们可以相互替换,且算法的变化不会影响使用算法的客户端。

2、策略模式的结构

策略模式包含三个核心角色:

  1. 策略接口(Strategy):定义所有支持的算法的公共接口

  2. 具体策略类(ConcreteStrategy):实现策略接口的具体算法

  3. 上下文类(Context):持有一个策略对象的引用,提供给客户端使用

策略模式结构

3、实际应用场景

假设我们正在开发一个电商系统,需要根据不同的支付方式(支付宝、微信、银行卡)处理支付操作。

传统if-else实现

public class PaymentService {
    public void pay(String paymentType, BigDecimal amount) {
        if ("ALIPAY".equals(paymentType)) {
            System.out.println("使用支付宝支付: " + amount);
            // 支付宝支付的具体逻辑
        } else if ("WECHAT".equals(paymentType)) {
            System.out.println("使用微信支付: " + amount);
            // 微信支付的具体逻辑
        } else if ("BANK_CARD".equals(paymentType)) {
            System.out.println("使用银行卡支付: " + amount);
            // 银行卡支付的具体逻辑
        } else {
            throw new IllegalArgumentException("不支持的支付方式");
        }
    }
}

这种实现方式存在明显问题:

  • 违反开闭原则,新增支付方式需要修改原有代码

  • 代码臃肿,难以维护

  • 条件判断逻辑复杂

实际开发中,这种是很常见的,不过我们还有更好的实现方式。

4、使用策略模式重构

4.1 定义策略接口

public interface PaymentStrategy {
    void pay(BigDecimal amount);
}

4.2 实现具体策略类

// 支付宝支付策略
public class AlipayStrategy implements PaymentStrategy {
    @Override
    public void pay(BigDecimal amount) {
        System.out.println("使用支付宝支付: " + amount);
        // 具体的支付宝支付逻辑
    }
}

// 微信支付策略
public class WechatPayStrategy implements PaymentStrategy {
    @Override
    public void pay(BigDecimal amount) {
        System.out.println("使用微信支付: " + amount);
        // 具体的微信支付逻辑
    }
}

// 银行卡支付策略
public class BankCardStrategy implements PaymentStrategy {
    @Override
    public void pay(BigDecimal amount) {
        System.out.println("使用银行卡支付: " + amount);
        // 具体的银行卡支付逻辑
    }
}

4.3 创建上下文类

public class PaymentContext {
    private PaymentStrategy strategy;
    
    public PaymentContext(PaymentStrategy strategy) {
        this.strategy = strategy;
    }
    
    public void setStrategy(PaymentStrategy strategy) {
        this.strategy = strategy;
    }
    
    public void executePayment(BigDecimal amount) {
        strategy.pay(amount);
    }
}

4.4 客户端使用

public class Client {
    public static void main(String[] args) {
        // 使用支付宝支付
        PaymentContext context = new PaymentContext(new AlipayStrategy());
        context.executePayment(100.0);
        
        // 切换到微信支付
        context.setStrategy(new WechatPayStrategy());
        context.executePayment(200.0);
        
        // 切换到银行卡支付
        context.setStrategy(new BankCardStrategy());
        context.executePayment(300.0);
    }
}

4.5 结合工厂模式优化

为了减轻客户端了解具体策略的负担,可以结合工厂模式:

public class PaymentStrategyFactory {
    private static final Map<String, PaymentStrategy> strategies = new HashMap<>();
    
    static {
        strategies.put("ALIPAY", new AlipayStrategy());
        strategies.put("WECHAT", new WechatPayStrategy());
        strategies.put("BANK_CARD", new BankCardStrategy());
    }
    
    public static PaymentStrategy getStrategy(String type) {
        PaymentStrategy strategy = strategies.get(type);
        if (strategy == null) {
            throw new IllegalArgumentException("不支持的支付方式: " + type);
        }
        return strategy;
    }
}

// 客户端使用
public class Client {
    public static void main(String[] args) {
        PaymentStrategy strategy = PaymentStrategyFactory.getStrategy("ALIPAY");
        PaymentContext context = new PaymentContext(strategy);
        context.executePayment(100.0);
    }
}

5、策略模式的优缺点

优点:

  1. 符合开闭原则:新增策略无需修改现有代码;

  2. 避免多重条件判断:消除了大量的if-else或switch-case语句;

  3. 提高代码复用性:算法可以复用在多个上下文中;

  4. 易于扩展和维护:每个策略类单独维护,职责单一。

缺点:

  1. 客户端必须了解所有策略:客户端需要知道有哪些策略以及它们的区别;

  2. 策略类数量增多:每个策略都需要一个单独的类,可能需要创建多个策略对象。

6、Java中的策略模式应用

Java标准库中有许多策略模式的应用,例如:

  1. Comparator接口:用于定义对象的比较策略;

  2. ThreadPoolExecutor中的RejectedExecutionHandler:处理任务拒绝策略;

  3. Java.security.Provider:提供加密算法策略;

Spring中的Bean实例化、AOP代理创建缓存管理事务管理等都用到了策略模式。

7、总结

策略模式通过将算法封装成独立的策略类,使得算法可以独立于客户端变化,提高了系统的灵活性和可扩展性。在实际开发中,策略模式常用于解决多重条件判断、算法选择等场景,是Java开发者必备的设计模式之一。

合理运用策略模式,可以使代码更加清晰、易于维护,并符合面向对象设计的原则。