Java中的策略模式

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

策略模式的核心组件

  1. 策略接口(Strategy Interface):定义所有支持的算法的公共接口
  2. 具体策略类(Concrete Strategy):实现策略接口的具体算法
  3. 上下文类(Context):维护对策略对象的引用,用策略接口与具体策略交互

介绍完毕,来看示例吧,案例分别是折扣活动及支付方式,都是些日常常见的场景

1:折扣活动

代码实现

首先是折扣的策略接口,定义一个折扣方法,具体折扣方法由其实现类自己实现

// 策略接口-折扣
interface DiscountStrategy {
    double applyDiscount(double originalPrice);
}

无折扣实现类

// 具体策略类-无折扣
class NoDiscountStrategy implements DiscountStrategy {
    @Override
    public double applyDiscount(double originalPrice) {
        return originalPrice;
    }
}

打折实现类

// 具体策略类-打折
class PercentageDiscountStrategy implements DiscountStrategy {
    private double percentage;
    
    public PercentageDiscountStrategy(double percentage) {
        this.percentage = percentage;
    }
    
    @Override
    public double applyDiscount(double originalPrice) {
        return originalPrice * (1 - percentage / 100);
    }
}

固定满减额实现类

// 具体策略类-减固定额
class FixedAmountDiscountStrategy implements DiscountStrategy {
    private double amount;
    
    public FixedAmountDiscountStrategy(double amount) {
        this.amount = amount;
    }
    
    @Override
    public double applyDiscount(double originalPrice) {
        return Math.max(0, originalPrice - amount);
    }
}

购物车

// 上下文类
class ShoppingCart {
    private DiscountStrategy discountStrategy;
    private double totalAmount;
    
    public ShoppingCart(DiscountStrategy discountStrategy) {
        this.discountStrategy = discountStrategy;
        this.totalAmount = 0;
    }
    
    public void setDiscountStrategy(DiscountStrategy discountStrategy) {
        this.discountStrategy = discountStrategy;
    }
    
    public void addItem(double price) {
        totalAmount += price;
    }
    
    public double calculateTotal() {
        return discountStrategy.applyDiscount(totalAmount);
    }
    
    public double getOriginalTotal() {
        return totalAmount;
    }
}

客户端代码

// 客户端代码
public class DiscountExample {
    public static void main(String[] args) {
        // 创建购物车,初始使用无折扣策略
        ShoppingCart cart = new ShoppingCart(new NoDiscountStrategy());
        
        // 添加商品
        cart.addItem(100);
        cart.addItem(50);
        cart.addItem(30);
        
        System.out.println("原价: " + cart.getOriginalTotal());
        System.out.println("无折扣: " + cart.calculateTotal());
        
        // 切换到百分比折扣
        cart.setDiscountStrategy(new PercentageDiscountStrategy(10)); // 9折
        System.out.println("9折后: " + cart.calculateTotal());
        
        // 切换到固定金额折扣
        cart.setDiscountStrategy(new FixedAmountDiscountStrategy(30)); // 减30
        System.out.println("减30后: " + cart.calculateTotal());
    }
}

在实际应用中,这种策略模式可以灵活的切换算法,若有新的折扣方式,直接新增算法并实现接口就可以。

2:支付方式

代码实现

支付策略接口

// 策略接口-支付方式
interface PaymentStrategy {
    boolean pay(double amount);
    String getPaymentMethod();
}

信用卡支付实现类

// 具体策略类-信用卡支付
class CreditCardPayment implements PaymentStrategy {
    private String cardNumber;
    private String expiryDate;
    private String cvv;
    
    public CreditCardPayment(String cardNumber, String expiryDate, String cvv) {
        this.cardNumber = cardNumber;
        this.expiryDate = expiryDate;
        this.cvv = cvv;
    }
    
    @Override
    public boolean pay(double amount) {
        // 模拟信用卡支付逻辑
        System.out.println("使用信用卡支付 " + amount + " 元");
        System.out.println("卡号: " + maskCardNumber(cardNumber));
        // 实际场景中这里会有真实的支付处理逻辑
        return true;
    }
    
    @Override
    public String getPaymentMethod() {
        return "信用卡";
    }
    
    private String maskCardNumber(String cardNumber) {
        if (cardNumber.length() <= 4) return cardNumber;
        return "****-****-****-" + cardNumber.substring(cardNumber.length() - 4);
    }
}

支付宝支付实现类

// 具体策略类-支付宝支付
class AlipayPayment implements PaymentStrategy {
    private String accountId;
    
    public AlipayPayment(String accountId) {
        this.accountId = accountId;
    }
    
    @Override
    public boolean pay(double amount) {
        // 模拟支付宝支付逻辑
        System.out.println("使用支付宝支付 " + amount + " 元");
        System.out.println("支付宝账号: " + accountId);
        // 实际场景中这里会有真实的支付处理逻辑
        return true;
    }
    
    @Override
    public String getPaymentMethod() {
        return "支付宝";
    }
}

微信支付实现类

// 具体策略类-微信支付
class WechatPayment implements PaymentStrategy {
    private String openId;
    
    public WechatPayment(String openId) {
        this.openId = openId;
    }
    
    @Override
    public boolean pay(double amount) {
        // 模拟微信支付逻辑
        System.out.println("使用微信支付 " + amount + " 元");
        System.out.println("微信OpenID: " + openId);
        // 实际场景中这里会有真实的支付处理逻辑
        return true;
    }
    
    @Override
    public String getPaymentMethod() {
        return "微信支付";
    }
}

支付类

// 上下文类
class PaymentProcessor {
    private PaymentStrategy paymentStrategy;
    
    public void setPaymentStrategy(PaymentStrategy paymentStrategy) {
        this.paymentStrategy = paymentStrategy;
    }
    
    public boolean processPayment(double amount) {
        if (paymentStrategy == null) {
            System.out.println("请先设置支付方式");
            return false;
        }
        
        System.out.println("开始处理支付...");
        System.out.println("支付方式: " + paymentStrategy.getPaymentMethod());
        System.out.println("支付金额: " + amount + " 元");
        
        boolean result = paymentStrategy.pay(amount);
        
        if (result) {
            System.out.println("支付成功!");
        } else {
            System.out.println("支付失败!");
        }
        
        return result;
    }
}

支付策略工厂
实际应用中可以将各种支付尺幅方式注册进来,在使用时由客户自己选择使用哪种支付方式

// 支付策略工厂(可选,用于管理支付策略)
class PaymentStrategyFactory {
    private Map<String, PaymentStrategy> strategies = new HashMap<>();
    
    public void registerStrategy(String key, PaymentStrategy strategy) {
        strategies.put(key, strategy);
    }
    
    public PaymentStrategy getStrategy(String key) {
        return strategies.get(key);
    }
}

客户端代码

// 客户端代码
public class PaymentExample {
    public static void main(String[] args) {
        // 创建支付处理器
        PaymentProcessor processor = new PaymentProcessor();
        
        // 创建支付策略工厂并注册策略
        PaymentStrategyFactory factory = new PaymentStrategyFactory();
        factory.registerStrategy("credit", new CreditCardPayment("1234-5678-9012-3456", "12/25", "123"));
        factory.registerStrategy("alipay", new AlipayPayment("user@alipay.com"));
        factory.registerStrategy("wechat", new WechatPayment("wx_openid_123456"));
        
        double amount = 299.99;
        
        // 使用信用卡支付
        System.out.println("=== 信用卡支付 ===");
        processor.setPaymentStrategy(factory.getStrategy("credit"));
        processor.processPayment(amount);
        
        System.out.println("\n=== 支付宝支付 ===");
        processor.setPaymentStrategy(factory.getStrategy("alipay"));
        processor.processPayment(amount);
        
        System.out.println("\n=== 微信支付 ===");
        processor.setPaymentStrategy(factory.getStrategy("wechat"));
        processor.processPayment(amount);
        
        // 动态切换支付方式的例子
        System.out.println("\n=== 动态切换支付方式 ===");
        simulateCheckoutProcess(processor, factory, amount);
    }
    
    private static void simulateCheckoutProcess(PaymentProcessor processor, 
                                               PaymentStrategyFactory factory, 
                                               double amount) {
        // 模拟用户选择不同的支付方式
        String[] paymentMethods = {"credit", "alipay", "wechat"};
        
        for (String method : paymentMethods) {
            System.out.println("\n尝试使用 " + method + " 支付:");
            processor.setPaymentStrategy(factory.getStrategy(method));
            boolean success = processor.processPayment(amount);
            
            if (success) {
                System.out.println("支付完成,退出支付流程");
                break;
            }
        }
    }
}

策略模式的优点

  1. 开闭原则:可以在不修改上下文的情况下引入新的策略
  2. 消除条件语句:避免使用大量的if-else或switch-case语句
  3. 算法复用:不同的上下文可以复用相同的策略
  4. 运行时切换:可以在运行时动态切换算法

策略模式的适用场景

  • 一个系统需要在多种算法中选择一种时
  • 有多个条件语句的类,且这些条件语句只是选择不同的行为时
  • 不希望客户端知道复杂的、与算法相关的数据结构时
  • 当不同的行为堆砌在一个类中时,可以将这些行为分解为多个策略类

更多推荐