第六节 Java编程的策略模式

亮子 2025-06-06 13:43:07 128 0 0 0

深入解析策略模式(Strategy Pattern)

策略模式是行为型设计模式中最常用且最灵活的模式之一,它通过定义算法族、封装每个算法,并使它们可以互相替换,让算法的变化独立于使用算法的客户端。

一、策略模式核心结构

1. 角色组成

  • 策略接口(Strategy Interface):定义所有支持的算法/策略的公共接口
  • 具体策略类(Concrete Strategies):实现策略接口的具体算法类
  • 上下文类(Context):持有一个策略对象的引用,通过接口与策略交互

2. UML类图

┌─────────────────┐       ┌──────────────────┐
│    Context      │       │   Strategy       │
├─────────────────┤       ├──────────────────┤
│ -strategy:Strategy│<>────│ +execute():void  │
├─────────────────┤       └──────────────────┘
│ +setStrategy()  │                 ▲
│ +executeStrategy()│               │
└─────────────────┘       ┌─────────┴──────────┐
                          │                    │
               ┌──────────────────┐  ┌──────────────────┐
               │ ConcreteStrategyA │  │ ConcreteStrategyB │
               ├──────────────────┤  ├──────────────────┤
               │ +execute()       │  │ +execute()       │
               └──────────────────┘  └──────────────────┘

二、完整代码示例

// 策略接口
public interface PaymentStrategy {
    void pay(double amount);
}

// 具体策略类
public class CreditCardPayment implements PaymentStrategy {
    private String cardNumber;
    private String cvv;
    
    public CreditCardPayment(String cardNumber, String cvv) {
        this.cardNumber = cardNumber;
        this.cvv = cvv;
    }
    
    @Override
    public void pay(double amount) {
        System.out.println("Paid " + amount + " using Credit Card");
    }
}

public class PayPalPayment implements PaymentStrategy {
    private String email;
    
    public PayPalPayment(String email) {
        this.email = email;
    }
    
    @Override
    public void pay(double amount) {
        System.out.println("Paid " + amount + " using PayPal");
    }
}

// 上下文类
public class ShoppingCart {
    private PaymentStrategy paymentStrategy;
    
    public void setPaymentStrategy(PaymentStrategy strategy) {
        this.paymentStrategy = strategy;
    }
    
    public void checkout(double amount) {
        paymentStrategy.pay(amount);
    }
}

// 客户端使用
public class Client {
    public static void main(String[] args) {
        ShoppingCart cart = new ShoppingCart();
        
        // 使用信用卡支付
        cart.setPaymentStrategy(new CreditCardPayment("1234-5678-9012-3456", "123"));
        cart.checkout(100.0);
        
        // 切换为PayPal支付
        cart.setPaymentStrategy(new PayPalPayment("user@example.com"));
        cart.checkout(50.0);
    }
}

三、策略模式深入特性

1. 运行时策略切换

策略模式允许在运行时动态改变对象的行为:

// 根据用户选择切换策略
if(userChoosesCreditCard()) {
    cart.setPaymentStrategy(new CreditCardPayment(...));
} else {
    cart.setPaymentStrategy(new PayPalPayment(...));
}

2. 消除条件语句

替代传统的if-else或switch-case语句:

// 传统方式
if(paymentType == CREDIT_CARD) {
    processCreditCard();
} else if(paymentType == PAYPAL) {
    processPayPal();
}

// 策略模式方式
paymentStrategy.process();

3. 开闭原则(OCP)的完美体现

新增策略时无需修改现有代码:

// 新增加密货币支付策略
public class CryptoPayment implements PaymentStrategy {
    @Override
    public void pay(double amount) {
        System.out.println("Paid " + amount + " using Bitcoin");
    }
}

// 使用新策略
cart.setPaymentStrategy(new CryptoPayment());

四、Java标准库中的应用实例

  1. Comparator接口
    java Collections.sort(list, new Comparator<T>() { public int compare(T o1, T o2) { return o1.compareTo(o2); // 可以替换不同的比较策略 } });

  2. ThreadPoolExecutor的拒绝策略
    java executor.setRejectedExecutionHandler( new ThreadPoolExecutor.AbortPolicy() // 可替换为其他拒绝策略 );

  3. Java Security的加密策略
    java Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");

五、策略模式高级应用

1. 策略工厂模式结合

public class PaymentStrategyFactory {
    public static PaymentStrategy getStrategy(PaymentType type) {
        switch(type) {
            case CREDIT_CARD: return new CreditCardPayment(...);
            case PAYPAL: return new PayPalPayment(...);
            case CRYPTO: return new CryptoPayment();
            default: throw new IllegalArgumentException();
        }
    }
}

// 使用
PaymentStrategy strategy = PaymentStrategyFactory.getStrategy(userChoice);

2. Spring中的策略模式

@Component
public class PaymentService {
    private Map<String, PaymentStrategy> strategies;
    
    @Autowired
    public PaymentService(List<PaymentStrategy> strategyList) {
        strategies = strategyList.stream()
            .collect(Collectors.toMap(
                s -> s.getClass().getSimpleName(),
                Function.identity()
            ));
    }
    
    public void processPayment(String strategyName, double amount) {
        strategies.get(strategyName).pay(amount);
    }
}

3. Lambda表达式简化策略

public class Calculator {
    private BinaryOperator<Double> operation;
    
    public void setStrategy(BinaryOperator<Double> strategy) {
        this.operation = strategy;
    }
    
    public double calculate(double a, double b) {
        return operation.apply(a, b);
    }
}

// 使用
calculator.setStrategy((a, b) -> a + b); // 加法策略
calculator.setStrategy((a, b) -> a * b); // 乘法策略

六、策略模式优劣分析

优点:

  1. 符合开闭原则:新增策略无需修改现有代码
  2. 避免多重条件判断:用组合替代条件分支
  3. 提高代码复用:策略实现可以在不同上下文中复用
  4. 运行时灵活性:可以动态切换算法

缺点:

  1. 客户端必须了解不同策略:需要知道有哪些策略及何时使用
  2. 策略类数量可能爆炸:每个策略需要一个单独类
  3. 通信开销:策略与上下文之间可能需要传递额外数据

七、策略模式适用场景

  1. 系统需要在多种算法中选择一种时
  2. 需要避免暴露复杂算法或数据结构时
  3. 一个类定义了多种行为,且这些行为以多个条件语句出现时
  4. 希望同一行为在不同场景下有不同实现时

八、与状态模式的区别

虽然结构相似,但两者意图不同:

特性 策略模式 状态模式
目的 灵活替换算法 对象内部状态改变时改变行为
切换方 客户端或上下文决定 由状态实现类自行控制状态转移
关注点 不同算法的实现 状态转换和状态相关行为
生命周期 策略通常独立于上下文 状态与上下文生命周期紧密相关

策略模式是处理“怎么做”的问题,而状态模式是处理“是什么状态”的问题。