模式定义

策略模式是一种行为型设计模式,它定义了一系列算法,并将每个算法封装起来,使它们可以互相替换。策略模式让算法的变化独立于使用算法的客户。通过策略模式,客户端可以选择不同的算法实现,而不需要修改客户端代码。

模式结构

graph TD A[Context] --> B[Strategy] B --> C[ConcreteStrategyA] B --> D[ConcreteStrategyB]

实现方式

基础实现

定义策略接口,实现具体策略类和上下文类。

// 策略接口
public interface SortStrategy {
    void sort(int[] array);
}

// 具体策略 - 冒泡排序
class BubbleSortStrategy implements SortStrategy {
    @Override
    public void sort(int[] array) {
        System.out.println("使用冒泡排序");
        int n = array.length;
        for (int i = 0; i < n - 1; i++) {
            for (int j = 0; j < n - i - 1; j++) {
                if (array[j] > array[j + 1]) {
                    // 交换元素
                    int temp = array[j];
                    array[j] = array[j + 1];
                    array[j + 1] = temp;
                }
            }
        }
    }
}

// 具体策略 - 快速排序
class QuickSortStrategy implements SortStrategy {
    @Override
    public void sort(int[] array) {
        System.out.println("使用快速排序");
        quickSort(array, 0, array.length - 1);
    }
    
    private void quickSort(int[] array, int low, int high) {
        if (low < high) {
            int pi = partition(array, low, high);
            quickSort(array, low, pi - 1);
            quickSort(array, pi + 1, high);
        }
    }
    
    private int partition(int[] array, int low, int high) {
        int pivot = array[high];
        int i = (low - 1);
        
        for (int j = low; j < high; j++) {
            if (array[j] <= pivot) {
                i++;
                int temp = array[i];
                array[i] = array[j];
                array[j] = temp;
            }
        }
        
        int temp = array[i + 1];
        array[i + 1] = array[high];
        array[high] = temp;
        
        return i + 1;
    }
}

// 上下文类
class SortContext {
    private SortStrategy strategy;
    
    public void setStrategy(SortStrategy strategy) {
        this.strategy = strategy;
    }
    
    public void executeSort(int[] array) {
        if (strategy != null) {
            strategy.sort(array);
        }
    }
}

使用示例

public class StrategyPatternDemo {
    public static void main(String[] args) {
        SortContext context = new SortContext();
        int[] array1 = {64, 34, 25, 12, 22, 11, 90};
        int[] array2 = {5, 2, 8, 1, 9, 3, 7};
        
        // 使用冒泡排序
        context.setStrategy(new BubbleSortStrategy());
        System.out.println("排序前: " + Arrays.toString(array1));
        context.executeSort(array1);
        System.out.println("排序后: " + Arrays.toString(array1));
        
        System.out.println("--------------------");
        
        // 使用快速排序
        context.setStrategy(new QuickSortStrategy());
        System.out.println("排序前: " + Arrays.toString(array2));
        context.executeSort(array2);
        System.out.println("排序后: " + Arrays.toString(array2));
    }
}

经典案例

1. Java Comparator比较器

Java集合框架中的Comparator接口是策略模式的经典应用:

List names = Arrays.asList("张三", "李四", "王五", "赵六");

// 按字典顺序排序(默认策略)
Collections.sort(names);
System.out.println("默认排序: " + names);

// 按长度排序(自定义策略)
Collections.sort(names, new Comparator() {
    @Override
    public int compare(String s1, String s2) {
        return s1.length() - s2.length();
    }
});
System.out.println("按长度排序: " + names);

// 使用Lambda表达式(Java 8+)
names.sort((s1, s2) -> s2.length() - s1.length());
System.out.println("按长度倒序: " + names);

2. Spring框架中的Resource接口

Spring框架中的Resource接口体现了策略模式的思想:

// 不同的Resource实现对应不同的资源访问策略
Resource fileResource = new FileSystemResource("data.txt");
Resource urlResource = new UrlResource("http://example.com/data.txt");
Resource classpathResource = new ClassPathResource("config.properties");

// 使用统一的接口访问不同类型的资源
InputStream inputStream = fileResource.getInputStream();
// ... 处理资源

3. 电商平台的促销策略

电商系统中根据不同条件应用不同的促销策略:

interface PromotionStrategy {
    double calculateDiscount(double originalPrice);
}

class FullReductionStrategy implements PromotionStrategy {
    private double threshold;
    private double reduction;
    
    public FullReductionStrategy(double threshold, double reduction) {
        this.threshold = threshold;
        this.reduction = reduction;
    }
    
    @Override
    public double calculateDiscount(double originalPrice) {
        return originalPrice >= threshold ? originalPrice - reduction : originalPrice;
    }
}

class DiscountStrategy implements PromotionStrategy {
    private double discountRate;
    
    public DiscountStrategy(double discountRate) {
        this.discountRate = discountRate;
    }
    
    @Override
    public double calculateDiscount(double originalPrice) {
        return originalPrice * discountRate;
    }
}

应用场景

优缺点

优点

  • 算法可以自由切换:可以在运行时动态地更换算法
  • 避免使用多重条件判断:用多态替代复杂的if-else或switch语句
  • 扩展性良好:增加新算法无需修改现有代码,符合开闭原则
  • 提高算法的保密性:每个算法都封装在独立的类中
  • 符合单一职责原则:每个算法类只负责一个特定的算法

缺点

  • 增加类的数量:每增加一个策略就需要增加一个类
  • 客户端必须知道所有的策略类:客户端需要知道有哪些策略并决定使用哪一个
  • 可能产生对象膨胀:如果策略过多,会产生大量的策略类