文章目录
- 一、策略模式
- 1.1 策略模式的定义
- 1.2 策略模式的参与者
- 1.3 策略模式的优点
- 1.4 策略模式的缺点
- 1.5 策略模式的使用场景
- 二、策略模式简单实现
- 2.1 案例描述
- 2.2 实现代码
- 三、策略模式的代码优化
- 3.1 优化思路
- 3.2 抽象策略接口
- 3.3 上下文
- 3.4 具体策略实现类
- 3.5 测试
- 参考资料
完整案例代码:java-demos/design-pattern-demos/strategy-pattern at main · idealzouhu/java-demos
一、策略模式
1.1 策略模式的定义
策略模式(Strategy Pattern)定义如下:
Define a family of algorithms,encapsulate each one,and make them interchangeable.(定义一组算法,将每个算法都封装起来,并且使它们之间可以互换。)
1.2 策略模式的参与者
策略模式的参与者主要有:
- Context(上下文类):它持有一个
Strategy
对象,用于调用具体策略的方法。客户端通常只需要与Context
交互,而不直接接触具体的策略实现。 - Strategy(策略接口):定义了算法的通用接口,所有具体策略都实现这个接口。
- ConcreteStrategy(具体策略类):实现
Strategy
接口的具体算法类,不同的策略类提供不同的算法实现。
1.3 策略模式的优点
- 避免使用多重条件判断:策略模式可以取代
if-else
或switch-case
的条件分支。
1.4 策略模式的缺点
- 策略数量可能会增多:如果策略太多,会增加类的数量,维护成本上升。如果 if-else 判断分支不多并且是固定的,那就使用策略模式即可。
1.5 策略模式的使用场景
- 算法/行为自由切换: 比如支付系统中,可以通过策略模式动态选择不同的支付方式(微信支付、支付宝支付、信用卡支付等)。
- 屏蔽算法底层细节:只用知道算法名字即可
二、策略模式简单实现
2.1 案例描述
假设我们有一个系统,它可以根据不同的需求选择不同的排序算法,比如快速排序、冒泡排序、归并排序等。通过策略模式,我们可以将这些不同的算法作为策略类进行实现。
2.2 实现代码
// 策略接口
interface SortStrategy {void sort(int[] array);
}// 具体策略类:快速排序
class QuickSortStrategy implements SortStrategy {@Overridepublic void sort(int[] array) {// 快速排序算法实现System.out.println("Using Quick Sort");// 排序逻辑}
}// 具体策略类:冒泡排序
class BubbleSortStrategy implements SortStrategy {@Overridepublic void sort(int[] array) {// 冒泡排序算法实现System.out.println("Using Bubble Sort");// 排序逻辑}
}// 上下文类:负责使用策略
class SortingContext {private SortStrategy strategy;// 设置策略public void setStrategy(SortStrategy strategy) {this.strategy = strategy;}// 执行排序public void executeSort(int[] array) {strategy.sort(array);}
}// 测试
public class StrategyPatternExample {public static void main(String[] args) {SortingContext context = new SortingContext();// 使用快速排序策略context.setStrategy(new QuickSortStrategy());context.executeSort(new int[]{3, 1, 2});// 使用冒泡排序策略context.setStrategy(new BubbleSortStrategy());context.executeSort(new int[]{3, 1, 2});}
}
三、策略模式的代码优化
3.1 优化思路
优化思路为使用 @Component
修饰具体策略类,从而让 Spring 提供的 IoC 容器自动添加策略类,从而实现开闭原则。
注意事项,如果你的策略实现类被初始化的时间晚于 onApplicationEvent
方法的调用,可能会导致在注册策略时未能找到这些策略。确保所有策略组件在 onApplicationEvent
被调用之前已经被创建和注册。
3.2 抽象策略接口
AbstractExecuteStrategy
定义了一个策略执行的基本框架,供具体策略类实现。主要方法有:
mark()
:默认返回策略标识的字符串,可以被具体策略类重写以返回唯一标识。patternMatchMark()
:用于模式匹配的标识,允许根据一定模式选择策略。execute(REQUEST requestParam)
:执行策略的方法,接受一个请求参数,默认实现为空,具体策略类可以重写。executeResp(REQUEST requestParam)
:执行策略并返回结果的方法,接受请求参数并返回响应,默认实现返回null
,具体策略类可以重写。
/*** 策略执行抽象接口**/
public interface AbstractExecuteStrategy<REQUEST, RESPONSE> {/*** 执行策略标识* 用于标识具体的执行策略**/default String mark() {return null;}/*** 执行策略范匹配标识* 用于在多个策略中通过模式匹配选择合适的策略执行**/default String patternMatchMark() {return null;}/*** 执行策略** @param requestParam 执行策略所需的参数,类型为REQUEST*/default void execute(REQUEST requestParam) {}/*** 执行策略,带有返回值** @param requestParam 执行策略所需的参数,类型为REQUEST* @return 执行策略后返回值,类型为RESPONSE*/default RESPONSE executeResp(REQUEST requestParam) {return null;}
}
3.3 上下文
AbstractStrategyChoose
类用于管理和选择具体的策略,并执行对应的策略。主要方法有:
-
choose(String mark, Boolean predicateFlag)
:如果predicateFlag为true,则进行模式匹配选择策略。如果predicateFlag为false,则直接根据 mark 查询策略。 -
chooseAndExecute(String mark, REQUEST requestParam)
:根据标识选择策略并执行,调用对应的
execute
方法。 -
chooseAndExecute(String mark, REQUEST requestParam, Boolean predicateFlag)
:根据标识和模式匹配标识选择策略并执行。 -
onApplicationEvent(ApplicationInitializingEvent event)
:实现ApplicationListener
接口,当Spring应用初始化时,自动注册所有的AbstractExecuteStrategy
实现类。
3.4 具体策略实现类
@Component
public class AddStrategy implements AbstractExecuteStrategy<Integer, Integer> {@Overridepublic String mark() {return "ADD";}@Overridepublic Integer executeResp(Integer requestParam) {return requestParam + 10; // 假设每次加10}}
3.5 测试
@SpringBootTest
class StrategyPatternApplicationTests {@Autowiredprivate AbstractStrategyChoose strategyChoose;@Testvoid testAddStrategy() {// 测试加法策略Integer addResult = strategyChoose.chooseAndExecuteResp("ADD", 20);System.out.println("Add Strategy Result: " + addResult); // 期望结果:30assertEquals(Integer.valueOf(30), addResult);}
}
参考资料
Java设计模式之策略模式(UML类图分析+代码详解)
12306: 完成高仿铁路 12306 用户 + 抢票 + 订单 + 支付服务