场景描述
在我们日常开发中,经常会有遇到这样的场景,前端传一个标识到后端,后端根据传过来标识的不同内容,做相应的业务处理;也会有这样的场景,后端查询订单状态,根据订单状态的不同,做相应的业务处理。
因此,我们经常会见到类似下面的代码:
public void biz(String orderId) {
Order order = orderMapper.getOderById(orderId);
if (order.getBussinessType() == 1) {
//批量开票
} else if (order.getBussinessType() == 2) {
//批量购买工作室
} else if (order.getBussinessType() == 3) {
//单个开票
} else if (order.getBussinessType() == 4) {
//单个购买工作室
} else {
System.out.println("业务类型无法处理");
}
}
根据不同的业务类型,做不同的业务,使用if else,看起来还挺清晰的,但是,这样写,尤其每个业务类型要处理的事情很多,代码很长,那上面这段代码就会显得很臃肿,并且较难维护和扩展。
解决办法(策略模式)
首先,我们来写一个世界上最简单的策略模式,让我们感受一把什么是策略模式。
//定义策略接口
public interface Strategy {
public int doOperation(int num1, int num2);
}
//策略1
public class OperationAdd implements Strategy{
@Override
public int doOperation(int num1, int num2) {
return num1 + num2;
}
}
//策略2
public class OperationSubtract implements Strategy{
@Override
public int doOperation(int num1, int num2) {
return num1 - num2;
}
}
//策略处理器
public class Context {
private Strategy strategy;
public Context(Strategy strategy){
this.strategy = strategy;
}
public int executeStrategy(int num1, int num2){
return strategy.doOperation(num1, num2);
}
}
public class StrategyPatternDemo {
public static void main(String[] args) {
Context context = new Context(new OperationAdd());
System.out.println("10 + 5 = " + context.executeStrategy(10, 5));
context = new Context(new OperationSubtract());
System.out.println("10 - 5 = " + context.executeStrategy(10, 5));
}
}
通过上面的例子,我们基于Spring来仿一个策略模式,重来来达到我们的需求。
step1 定义枚举(后续要使用到,用于管理多种业务类型)
package com.longer.test;
import lombok.Getter;
/**
* 业务类型枚举
* @author Longer
*/
public enum OriginBusinessType {
/**
* 批量开票
*/
BATCH_INVOICE(1, "批量开票", "batchInvoiceSolver"),
/**
* 批量购买工作室
*/
CREATE_STUDIO(2, "批量购买工作室", "batchBuyStudioSolver"),
/**
* 单个开票
*/
SINGLE_INVOICE(3, "单个开票", "singleInvoiceSolver"),
/**
* 单个购买工作室
*/
BUY_STUDIO(4, "单个购买工作室", "buyStudioSolver");
/**
* 业务类型
*/
@Getter
private int code;
/**
* 策略类名(多种策略,每中策略对应一个类名)
*/
@Getter
private String className;
/**
* 业务类型描述
*/
@Getter
private String desc;
OriginBusinessType(int code, String desc, String className) {
this.className = className;
this.code = code;
this.desc = desc;
}
public static String getClassNameByCode(int code) {
String className = "";
OriginBusinessType[] values = OriginBusinessType.values();
for (OriginBusinessType value : values) {
if (value.getCode() == code) {
className = value.getClassName();
}
}
return className;
}
}
step2 定义策略接口
public interface OrderStrategy {
/**
* 执行方法
* @param order
*/
void solve(Order order);
}
step3 定义各种策略
/**
* 批量购买工作室
*/
@Component
public class BatchBuyStudioSolver implements OrderStrategy{
@Override
public void solve(Order order) {
System.out.println("执行批量购买工作室业务");
}
}
@Component
public class BatchInvoiceSolver implements OrderStrategy{
@Override
public void solve(Order order) {
System.out.println("执行批量开票业务");
}
}
/**
* 单个购买工作室
*/
@Component
public class BuyStudioSolver implements OrderStrategy{
@Override
public void solve(Order order) {
System.out.println("执行单个购买工作室业务");
}
}
/**
* 单个开票
*/
@Component
public class SingleInvoiceSolver implements OrderStrategy{
@Override
public void solve(Order order) {
System.out.println("单个开票");
}
}
step4 定义策略处理器
/**
* 策略处理器
*/
@Component
public class OrderStrategySolver implements ApplicationContextAware {
/**
* 策略存储容器
*/
private Map<String, OrderStrategy> chooseMap = new HashMap<>();
private ApplicationContext context ;
public OrderStrategy getStrategy(String className){
return chooseMap.get(className);
}
/**
* 将各种策略对象加载进chooseMap容器里
*/
@PostConstruct
public void register() {
Map<String, OrderStrategy> solverMap = context.getBeansOfType(OrderStrategy.class);
for (String key : solverMap.keySet()) {
chooseMap.put(key,solverMap.get(key));
}
}
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
this.context = applicationContext;
}
}
说明:
实现ApplicationContextAware接口:在服务启动时,可以通过applicationContext获取容器里面的bean。
@PostConstruct:容器加载servlet时,执行该方法。
Last 看效果
策略模式代码写到这就差不多结束了。那么现在我们来看看效果:
文章开头那该死的if esle,现在只用如下一行代码就可以替代掉了。
orderStrategySolver.getStrategy(OriginBusinessType.getClassNameByCode(order.getBussinessType())).solve(order);