扫码关注公众号:芋道源码

发送: 百事可乐
获取永久解锁本站全部文章的链接

《Dubbo 实现原理与源码解析 —— 精品合集》 《Netty 实现原理与源码解析 —— 精品合集》
《Spring 实现原理与源码解析 —— 精品合集》 《MyBatis 实现原理与源码解析 —— 精品合集》
《Spring MVC 实现原理与源码解析 —— 精品合集》 《数据库实体设计合集》
《Spring Boot 实现原理与源码解析 —— 精品合集》 《Java 面试题 + Java 学习指南》

摘要: 原创出处 https://juejin.im/post/5d12228de51d45775c73dd1b 「坚持就是胜利」欢迎转载,保留摘要,谢谢!


🙂🙂🙂关注微信公众号:【芋道源码】有福利:

  1. RocketMQ / MyCAT / Sharding-JDBC 所有源码分析文章列表
  2. RocketMQ / MyCAT / Sharding-JDBC 中文注释源码 GitHub 地址
  3. 您对于源码的疑问每条留言将得到认真回复。甚至不知道如何读源码也可以请教噢
  4. 新的源码解析文章实时收到通知。每周更新一篇左右
  5. 认真的源码交流微信群。

前段时间,我将公司系统中的批量审单的功能进行了重构,用到了java的并发编程进行异步化处理,数据库的乐观锁机制处理多线程并发更新数据。其中批量审单的业务处理涉及到多种任务类型,对应不同的业务方法进行处理,比如转仓,转快递,添加赠品,删除赠品,拆分订单,批量驳回,批量作废等等,其中就用到了策略模式。

if else模式

if ("BATCH_CHANGE_WAREHOUSE".equals(taskType)) {
//批量转仓逻辑
} else if ("BATCH_CHANGE_SHIPPING".equals(taskType)) {
//批量转快递逻辑
} else if ("BATCH_REPLACE_ORDER_GOODS".equals(taskType)) {
//批量替换订单商品逻辑
} else if ("BATCH_DELETE_ORDER_GOODS".equals(taskType)) {
//批量删除订单商品逻辑
} else if ("BATCH_ADD_MEMO".equals(taskType)) {
//批量添加备注逻辑
} else {
//任务类型未知
System.out.println("任务类型无法处理");
}

看起来,思路清晰,if,else分支也很清楚,但不觉得代码很臃肿,维护起来麻烦吗,尤其是其他人来接锅的时候,连看下去的欲望都没有了。这时候你需要用策略模式消除其中的if else,进行一下简单的重构!

策略模式

1、首先抽象业务处理器

public abstract class InspectionSolver {

public abstract void solve(Long orderId, Long userId);

public abstract String[] supports();
}

2、将业务处理器和其支持处理的类型放到一个容器中,java里Map就是最常用的容器之一

@Component
public class InspectionSolverChooser implements ApplicationContextAware{


private Map<String, InspectionSolver> chooseMap = new HashMap<>();

public InspectionSolver choose(String type) {
return chooseMap.get(type);
}

@PostConstruct
public void register() {
Map<String, InspectionSolver> solverMap = context.getBeansOfType(InspectionSolver.class);
for (InspectionSolver solver : solverMap.values()) {
for (String support : solver.supports()) {
chooseMap.put(support,solver);
}
}
}

private ApplicationContext context;

@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
this.context=applicationContext;
}
}

这里是在应用启动的时候,加载spring容器中所有InspectionSolver类型的处理器,放到InspectionSolverChooser的map容器中。注意是InspectionSolver类型,所以定义的处理器都得继承InspectionSolver,其次是spring容器中的才能加载,所以定义的处理器都得放到spring容器中(@Component注解不能少)

3、定义不同的处理器

@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};
}
}

@Component
public class ReplaceOrderGoodsSolver 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_REPLACE_ORDER_GOODS};
}
}

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);
}
}

在测试类中我消除了可能一长段的if else,从选择器InspectionSolverChooser中根据type的不同取出不同的任务处理器InspectionSolver,然后调用其solve()方法进行任务处理,不同处理器调用的当然就是不同的solve()方法了,目的达到。

文章目录
  1. 1. if else模式
  2. 2. 策略模式
    1. 2.1. 1、首先抽象业务处理器
    2. 2.2. 2、将业务处理器和其支持处理的类型放到一个容器中,java里Map就是最常用的容器之一
    3. 2.3. 3、定义不同的处理器
    4. 2.4. 4、测试类