设计模式-策略模式(if else的终结者)

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

设计模式-策略模式

  • 概念

策略模式(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。前面的 ChangeWarehouseSolverChangeShippingSolver 两个策略实现类使用@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="开始配送";
}

测试结果
在这里插入图片描述
这里执行的是转入仓库的业务

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值