策略模式:算法的自由王国

摘要

策略模式是行为型设计模式中的"算法封装大师",它定义了一系列算法,并将每个算法封装起来,使它们可以相互替换。本文将深入探讨策略模式的核心思想、实现方式、应用场景及高级变体,通过丰富的Java代码示例展示如何构建灵活可扩展的算法系统,并分析其与状态模式、模板方法模式的区别与适用场景。

一、策略模式核心思想

策略模式的核心是分离算法定义与使用,具有以下关键特征:

  1. 算法封装:每个算法被封装在独立的策略类中
  2. 动态切换:运行时可以自由切换不同策略
  3. 消除条件分支:避免复杂的if-else或switch-case语句
  4. 开闭原则:新增算法无需修改现有代码

适用场景:

  • 系统需要在多种算法间动态切换
  • 需要避免使用多重条件选择语句
  • 算法需要独立于使用它们的客户端
  • 需要隐藏算法实现细节

二、策略模式结构解析

UML类图示意

[Context] o--> [Strategy]
[Strategy] <|-- [ConcreteStrategyA]
[Strategy] <|-- [ConcreteStrategyB]
[Strategy] <|-- [ConcreteStrategyC]

核心组件角色

角色 职责 典型实现
Strategy 策略接口 定义算法方法的接口
ConcreteStrategy 具体策略 实现策略接口的具体算法类
Context 上下文 持有策略引用并执行算法

三、基础实现:支付系统案例

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

// 具体策略:信用卡支付
class CreditCardStrategy implements PaymentStrategy {
    private String cardNumber;
    private String cvv;
    
    public CreditCardStrategy(String cardNumber, String cvv) {
        this.cardNumber = cardNumber;
        this.cvv = cvv;
    }
    
    @Override
    public void pay(double amount) {
        System.out.printf("Paying %.2f with credit card: %s\n", amount, maskCardNumber());
    }
    
    private String maskCardNumber() {
        return "****-****-****-" + cardNumber.substring(12);
    }
}

// 具体策略:PayPal支付
class PayPalStrategy implements PaymentStrategy {
    private String email;
    
    public PayPalStrategy(String email) {
        this.email = email;
    }
    
    @Override
    public void pay(double amount) {
        System.out.printf("Paying %.2f with PayPal account: %s\n", amount, email);
    }
}

// 具体策略:加密货币支付
class CryptoStrategy implements PaymentStrategy {
    private String walletAddress;
    
    public CryptoStrategy(String walletAddress) {
        this.walletAddress = walletAddress;
    }
    
    @Override
    public void pay(double amount) {
        System.out.printf("Paying %.2f with cryptocurrency to: %s\n", amount, walletAddress);
    }
}

// 上下文:购物车
class ShoppingCart {
    private PaymentStrategy paymentStrategy;
    private List<Item> items = new ArrayList<>();
    
    public void setPaymentStrategy(PaymentStrategy strategy) {
        this.paymentStrategy = strategy;
    }
    
    public void addItem(Item item) {
        items.add(item);
    }
    
    public void checkout() {
        double total = calculateTotal();
        paymentStrategy.pay(total);
    }
    
    private double calculateTotal() {
        return items.stream().mapToDouble(Item::getPrice).sum();
    }
}

// 客户端使用
public class PaymentDemo {
    public static void main(String[] args) {
        ShoppingCart cart = new ShoppingCart();
        cart.addItem(new Item("Laptop", 1200));
        cart.addItem(new Item("Headphones", 150));
        
        // 选择支付策略
        cart.setPaymentStrategy(new CreditCardStrategy("1234567812345678", "123"));
        cart.checkout();
        
        // 切换支付策略
        cart.setPaymentStrategy(new PayPalStrategy("user@example.com"));
        cart.checkout();
        
        // 切换支付策略
        cart.setPaymentStrategy(new CryptoStrategy("0x742d35Cc6634C0532925a3b844Bc454e4438f44e"));
        cart.checkout();
    }
}

四、高级应用:动态算法选择

1. 策略工厂模式

class StrategyFactory {
    private Map<String, PaymentStrategy> strategies = new HashMap<>();
    
    public StrategyFactory() {
        // 注册默认策略
        registerStrategy("credit", (card, cvv) -> new CreditCardStrategy(card, cvv));
        registerStrategy("paypal", (email, _) -> new PayPalStrategy(email));
        registerStrategy("crypto", (address, _) -> new CryptoStrategy(address));
    }
    
    public void registerStrategy(String type, BiFunction<String, String, PaymentStrategy> creator) {
        strategies.put(type, creator);
    }
    
    public PaymentStrategy getStrategy(String type, String param1, String param2) {
        PaymentStrategy strategy = strategies.get(type);
        if (strategy == null) {
            throw new IllegalArgumentException("Unknown strategy type: " + type);
        }
        return strategy;
    }
}

// 使用示例
StrategyFactory factory = new StrategyFactory();
PaymentStrategy strategy = factory.getStrategy("credit", "1234567812345678", "123");

2. 策略组合

// 组合策略
class CompositeStrategy implements PaymentStrategy {
    private List<PaymentStrategy> strategies;
    private double[] ratios;
    
    public CompositeStrategy(List<PaymentStrategy> strategies, double[] ratios) {
        this.strategies = strategies;
        this.ratios = ratios;
    }
    
    @Override
    public void pay(double totalAmount) {
        for (int i = 0; i < strategies.size(); i++) {
            double amount = totalAmount * ratios[i];
            strategies.get(i).pay(amount);
        }
    }
}

// 使用示例
PaymentStrategy credit = new CreditCardStrategy("1234567812345678", "123");
PaymentStrategy paypal = new PayPalStrategy("user@example.com");

CompositeStrategy splitPayment = new CompositeStrategy(
    Arrays.asList(credit, paypal),
    new double[]{0.7, 0.3} // 70%信用卡,30%PayPal
);

cart.setPaymentStrategy(splitPayment);
cart.checkout();

五、策略模式在复杂系统中的应用

1. 电商定价系统

// 定价策略接口
interface PricingStrategy {
    double calculatePrice(Product product, int quantity);
}

// 具体策略:标准定价
class StandardPricing implements PricingStrategy {
    public double calculatePrice(Product product, int quantity) {
        return product.getBasePrice() * quantity;
    }
}

// 具体策略:批量折扣
class BulkDiscountPricing implements PricingStrategy {
    private int threshold;
    private double discountRate;
    
    public BulkDiscountPricing(int threshold, double discountRate) {
        this.threshold = threshold;
        this.discountRate = discountRate;
    }
    
    public double calculatePrice(Product product, int quantity) {
        double basePrice = product.getBasePrice();
        if (quantity >= threshold) {
            return basePrice * quantity * (1 - discountRate);
        }
        return basePrice * quantity;
    }
}

// 具体策略:会员定价
class MemberPricing implements PricingStrategy {
    private double memberDiscount;
    
    public MemberPricing(double memberDiscount) {
        this.memberDiscount = memberDiscount;
    }
    
    public double calculatePrice(Product product, int quantity) {
        return product.getBasePrice() * quantity * (1 - memberDiscount);
    }
}

// 定价上下文
class PricingContext {
    private PricingStrategy strategy;
    
    public void setStrategy(PricingStrategy strategy) {
        this.strategy = strategy;
    }
    
    public double calculateTotal(Order order) {
        double total = 0;
        for (OrderItem item : order.getItems()) {
            total += strategy.calculatePrice(item.getProduct(), item.getQuantity());
        }
        return total;
    }
}

// 使用示例
Order order = getCurrentOrder();
PricingContext context = new PricingContext();

// 普通用户使用标准定价
context.setStrategy(new StandardPricing());
double standardTotal = context.calculateTotal(order);

// 批量采购用户
context.setStrategy(new BulkDiscountPricing(10, 0.15));
double bulkTotal = context.calculateTotal(order);

// 会员用户
context.setStrategy(new MemberPricing(0.1));
double memberTotal = context.calculateTotal(order);

2. 游戏AI行为系统

// AI行为策略
interface AIBehavior {
    void performAction(GameCharacter character, GameContext context);
}

// 攻击行为
class AggressiveBehavior implements AIBehavior {
    public void performAction(GameCharacter character, GameContext context) {
        Character target = findNearestEnemy(character, context);
        if (target != null) {
            character.attack(target);
        } else {
            character.moveToRandomPosition();
        }
    }
}

// 防御行为
class DefensiveBehavior implements AIBehavior {
    public void performAction(GameCharacter character, GameContext context) {
        if (character.getHealth() < 30) {
            character.useHealingItem();
        } else {
            character.defend();
        }
    }
}

// 逃跑行为
class FleeingBehavior implements AIBehavior {
    public void performAction(GameCharacter character, GameContext context) {
        if (character.getHealth() < 20) {
            character.moveToSafeZone();
        } else {
            // 低概率随机移动
            if (Math.random() < 0.3) {
                character.moveToRandomPosition();
            }
        }
    }
}

// AI控制器
class AIController {
    private AIBehavior currentBehavior;
    
    public void setBehavior(AIBehavior behavior) {
        this.currentBehavior = behavior;
    }
    
    public void update(GameCharacter character, GameContext context) {
        currentBehavior.performAction(character, context);
    }
}

// 使用示例
GameCharacter enemy = new GameCharacter();
AIController ai = new AIController();

// 根据情境切换行为
if (enemy.getHealth() > 70) {
    ai.setBehavior(new AggressiveBehavior());
} else if (enemy.getHealth() > 30) {
    ai.setBehavior(new DefensiveBehavior());
} else {
    ai.setBehavior(new FleeingBehavior());
}

// 游戏循环中
while (gameRunning) {
    ai.update(enemy, gameContext);
    // 其他游戏逻辑...
}

六、策略模式优缺点分析

优点:

优点 说明
开闭原则 新增策略无需修改现有代码
消除条件语句 避免复杂的条件分支
算法复用 策略可在不同上下文中复用
运行时切换 动态改变对象行为
算法封装 隐藏实现细节,提高内聚性

缺点:

缺点 说明
类数量增加 每个策略都需要单独类
客户端需了解策略 客户端需知道不同策略的区别
通信开销 策略间共享数据需通过上下文
过度设计风险 简单算法可能不需要策略模式

七、策略模式与其他模式对比

策略模式 vs 状态模式

维度 策略模式 状态模式
目的 封装算法 管理状态转换
切换机制 客户端显式切换 状态自动转换
关注点 算法实现 状态行为
依赖关系 策略相互独立 状态相互了解

策略模式 vs 模板方法模式

维度 策略模式 模板方法模式
实现方式 组合 继承
扩展点 完整算法替换 算法步骤扩展
灵活性 运行时切换 编译时确定
代码复用 策略对象复用 父类代码复用

八、策略模式最佳实践

1. 策略枚举实现

enum CalculatorStrategy implements DoubleBinaryOperator {
    ADD {
        public double applyAsDouble(double a, double b) {
            return a + b;
        }
    },
    SUBTRACT {
        public double applyAsDouble(double a, double b) {
            return a - b;
        }
    },
    MULTIPLY {
        public double applyAsDouble(double a, double b) {
            return a * b;
        }
    },
    DIVIDE {
        public double applyAsDouble(double a, double b) {
            if (b == 0) throw new ArithmeticException("Division by zero");
            return a / b;
        }
    };
}

// 使用示例
double result = CalculatorStrategy.ADD.applyAsDouble(5, 3); // 8.0

2. 策略与Lambda表达式

class TextProcessor {
    private Function<String, String> processingStrategy;
    
    public TextProcessor() {
        // 默认策略:无操作
        this.processingStrategy = Function.identity();
    }
    
    public void setProcessingStrategy(Function<String, String> strategy) {
        this.processingStrategy = strategy;
    }
    
    public String processText(String input) {
        return processingStrategy.apply(input);
    }
}

// 使用示例
TextProcessor processor = new TextProcessor();

// 设置大写转换策略
processor.setProcessingStrategy(String::toUpperCase);
System.out.println(processor.processText("hello")); // HELLO

// 设置反转策略
processor.setProcessingStrategy(s -> new StringBuilder(s).reverse().toString());
System.out.println(processor.processText("hello")); // olleh

// 设置自定义策略
processor.setProcessingStrategy(s -> s.replaceAll("l", "L"));
System.out.println(processor.processText("hello")); // heLLo

3. 策略缓存与重用

class StrategyCache {
    private Map<String, PricingStrategy> cache = new HashMap<>();
    
    public PricingStrategy getStrategy(String strategyType) {
        return cache.computeIfAbsent(strategyType, type -> {
            switch (type) {
                case "standard": return new StandardPricing();
                case "bulk": return new BulkDiscountPricing(10, 0.15);
                case "member": return new MemberPricing(0.1);
                default: throw new IllegalArgumentException("Unknown strategy");
            }
        });
    }
}

// 使用示例
StrategyCache strategyCache = new StrategyCache();
PricingStrategy bulkStrategy = strategyCache.getStrategy("bulk");

九、策略模式在开源框架中的应用

Spring框架中的策略模式

// Spring的资源加载策略
ResourceLoader loader = new DefaultResourceLoader();
Resource resource = loader.getResource("classpath:config.xml");

// 内部实现:不同资源位置的策略
public interface ResourcePatternResolver {
    Resource[] getResources(String locationPattern) throws IOException;
}

// 具体策略实现
public class PathMatchingResourcePatternResolver implements ResourcePatternResolver {
    // 实现资源匹配算法
}

Java Collections排序策略

List<String> names = Arrays.asList("Alice", "Bob", "Charlie");

// 使用不同排序策略
Collections.sort(names); // 自然顺序
Collections.sort(names, Collections.reverseOrder()); // 逆序
Collections.sort(names, String.CASE_INSENSITIVE_ORDER); // 忽略大小写

// 自定义排序策略
Collections.sort(names, (a, b) -> b.length() - a.length()); // 按长度降序

十、策略模式演进:函数式策略

函数式接口作为策略

@FunctionalInterface
interface ValidationStrategy {
    boolean validate(String input);
}

class Validator {
    private ValidationStrategy strategy;
    
    public Validator(ValidationStrategy strategy) {
        this.strategy = strategy;
    }
    
    public boolean validate(String input) {
        return strategy.validate(input);
    }
}

// 使用示例
Validator numericValidator = new Validator(s -> s.matches("\\d+"));
boolean isNumeric = numericValidator.validate("12345"); // true

Validator emailValidator = new Validator(s -> s.matches("[a-z]+@[a-z]+\\.[a-z]{2,3}"));
boolean isEmail = emailValidator.validate("user@example.com"); // true

策略组合与管道

class ValidationPipeline {
    private List<ValidationStrategy> strategies = new ArrayList<>();
    
    public ValidationPipeline addStrategy(ValidationStrategy strategy) {
        strategies.add(strategy);
        return this;
    }
    
    public boolean validate(String input) {
        for (ValidationStrategy strategy : strategies) {
            if (!strategy.validate(input)) {
                return false;
            }
        }
        return true;
    }
}

// 使用示例
ValidationPipeline pipeline = new ValidationPipeline()
    .addStrategy(s -> s.length() >= 8) // 最小长度
    .addStrategy(s -> s.matches(".*[A-Z].*")) // 包含大写字母
    .addStrategy(s -> s.matches(".*[0-9].*")); // 包含数字

boolean isValid = pipeline.validate("Password123"); // true

总结

策略模式是构建灵活算法系统的核心设计模式,它通过以下方式提升系统质量:

  1. 解耦算法:将算法从业务逻辑中分离
  2. 提升扩展性:新增算法不影响现有代码
  3. 增强可维护性:消除复杂条件分支
  4. 支持运行时决策:动态切换不同策略

现代应用趋势:

  • 函数式策略:Lambda表达式简化策略实现
  • 策略自动选择:基于规则的策略选择机制
  • 策略组合:构建复杂行为管道
  • 微服务策略:分布式系统中的策略服务

在应用策略模式时需注意:

  • 避免过度细分:合理确定策略粒度
  • 策略管理:使用工厂模式管理策略创建
  • 上下文设计:合理设计策略与上下文的交互
  • 性能考量:高频切换策略时的性能影响

策略模式是现代软件架构中不可或缺的设计工具,特别是在需要灵活算法和业务规则的系统中。掌握策略模式的精髓,将帮助开发者构建出更加灵活、可扩展和易维护的系统架构。