设计模式-策略模式
策略模式(Strategy),定义了一组算法,将每个算法都封装起来,并且使它们之间可以互换,可以针对不同业务选择不同逻辑的执行。
-
场景应用
有一笔订单需要对它进行流程管理。从订单产生->订单入库->配送->确认订单完成,有这样一个流程。这里有订单入库、配送这两个动作标签,在每个订单产生动作标签的时候,执行的不同的业务处理。这里用简单的分支语句来实现就是:
如果这里的分支有很多层,那么这块代码复杂度就会很高,而且也不容易维护。if(action=="订单入库") { //执行业务代码 }else if(action=="配送"){ //执行业务代码 } ......
下面使用策略模式实现。 -
策略模式实现
1. 抽象出业务处理器,可以当做分支结构中选择器。这个只是抽象出来的模型,后面需要给他具体实现。
public abstract class InspectionSolver {
/**
* 业务代码抽象
* @param orderId
* @param userId
*/
public abstract void solve(Long orderId, Long userId);
/**
* 策略标识,决定执行哪一个策略
* @return
*/
public abstract String[] supports();
}
2. 根据抽象模型定义出自己的业务处理器,这就是实际的业务代码,当系统确定你要执行的业务后,就会执行相应的业务代码进行处理。
//继承抽象业务处理器并实现自己的业务处理,
//可以根据supports中拥有的动作绑定相应的业务代码
//订单批量转仓
@Component
public class ChangeWarehouseSolver extends InspectionSolver {
@Override
public void solve(Long orderId, Long userId) {
System.out.println("订单"+orderId+"开始进行批量转仓了。。");
}
@Override
public String[] supports() {
return new String[] {InspectionConstant.INSPECTION_TASK_TYPE_BATCH_CHANGE_WAREHOUSE};
}
}
//订单转换快递
@Component
public class ChangeShippingSolver extends InspectionSolver {
@Override
public void solve(Long orderId, Long userId) {
System.out.println("订单"+orderId+"开始进行转快递了。。");
}
@Override
public String[] supports() {
return new String[] {InspectionConstant.INSPECTION_TASK_TYPE_BATCH_CHANGE_SHIPPING}; }
}
3. 现在策略是有了,所以还需要个调用的过程。想要根据不同的策略执行不同的逻辑业务,需要运用AOP切面得到当前所有具体的策略实现类。然后将对应的supports字段和对应的策略实现类存放在一个Map中。通过Map中的Key-Value就能知道对应的动作的策略,从而实现一个动态处理逻辑的过程。
@Component
public class InspectionSolverChooser implements ApplicationContextAware {
private Map<String, InspectionSolver> chooseMap = new HashMap<>();
private ApplicationContext context;
@PostConstruct
public void register(){
System.out.println("执行PostConstruct...");
Map<String, InspectionSolver> solverMap = context.getBeansOfType(InspectionSolver.class);
for (InspectionSolver solver : solverMap.values()) {
for (String support : solver.supports()) {
chooseMap.put(support,solver);
}
}
}
public InspectionSolver choose(String type){
return chooseMap.get(type);
}
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
this.context=applicationContext;
System.out.println("applicationc初始化。。。");
}
}
这里通过实现ApplicationContextAware这个上下文接口,可以获取所有在Spring中托管的bean。前面的 ChangeWarehouseSolver 和 ChangeShippingSolver 两个策略实现类使用@Component注解过,让他们在Spring容器中注册过bean,solverMap 这个Map是用在存放获取Spring容器中的InspectionSolver bean,chooseMap 这个Map用来存放策略对应的业务。再通过***choose(type)*** 这个方法调用,得到不同动作类型的策略,实现业务处理。
- @PostConstruct
这里在说下@PostConstruct这个注解。当一个类中construct构造方法、@Autowired、@PostConstruct的执行优先级是construct>Autowired>PostConstruct。所以当我们想要使用@Autowired注入的bean的时候,使用构造函数肯定获取不到bean,那么可以把相应的操作放到@PostConstruct这个注解下使用。
4. 策略模式使用
编写测试类
@RunWith(SpringJUnit4ClassRunner.class)
@SpringBootTest(classes= Application.class)// 指定spring-boot的启动类
public class InspectionTest {
@Autowired
private InspectionSolverChooser chooser;
@Test
public void test() throws Exception{
//准备执行动作 转入仓库
String taskType = InspectionConstant.INSPECTION_TASK_TYPE_BATCH_CHANGE_WAREHOUSE;
Long orderId = 12345L;
Long userId = 123L;
//获取任务类型对应的solver
InspectionSolver solver = chooser.choose(taskType);
if (solver == null) {
throw new RuntimeException("任务类型暂时无法处理!");
}
//调用不同solver的方法进行处理
solver.solve(orderId,userId);
}
}
系统枚举类
public enum InspectionConstant {
public static String INSPECTION_TASK_TYPE_BATCH_CHANGE_WAREHOUSE="转入仓库";
public static String INSPECTION_TASK_TYPE_BATCH_CHANGE_SHIPPING="开始配送";
}
测试结果

这里执行的是转入仓库的业务
本文深入解析策略模式的概念与应用场景,通过实例展示如何利用策略模式封装一组算法,使其能在不同业务场景下灵活互换,有效降低代码复杂度,提高可维护性。
2912

被折叠的 条评论
为什么被折叠?



