策略模式 (Strategy Pattern)
定义一系列算法,把它们一个个封装起来,并且使它们可互相替换
模式定义
策略模式是一种行为型设计模式,它定义了一系列算法,并将每个算法封装起来,使它们可以互相替换。策略模式让算法的变化独立于使用算法的客户。通过策略模式,客户端可以选择不同的算法实现,而不需要修改客户端代码。
模式结构
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;
}
}
应用场景
- 多种算法实现:根据不同条件选择不同的排序或查找算法
- 表单验证:根据不同类型的表单选择不同的验证策略
- 支付方式:支持多种支付方式(信用卡、支付宝、微信等)
- 路由算法:网络路由中根据不同条件选择不同的路由策略
- 压缩算法:支持多种压缩格式(ZIP、RAR、7Z等)
- 缓存策略:支持多种缓存淘汰策略(LRU、FIFO等)
优缺点
优点
- 算法可以自由切换:可以在运行时动态地更换算法
- 避免使用多重条件判断:用多态替代复杂的if-else或switch语句
- 扩展性良好:增加新算法无需修改现有代码,符合开闭原则
- 提高算法的保密性:每个算法都封装在独立的类中
- 符合单一职责原则:每个算法类只负责一个特定的算法
缺点
- 增加类的数量:每增加一个策略就需要增加一个类
- 客户端必须知道所有的策略类:客户端需要知道有哪些策略并决定使用哪一个
- 可能产生对象膨胀:如果策略过多,会产生大量的策略类