Some time ago, I reconstructed the function of batch review in the company system, using Java concurrent programming for asynchronous processing, and optimistic locking mechanism of the database to deal with multi-thread concurrent data update. Among them, the business processing of batch review documents involves a variety of task types, corresponding to different business methods for processing, such as warehouse transfer, transfer express, add gifts, delete gifts, split orders, batch rejection, batch nullification and so on, which uses the strategy mode.

If the else mode

        if ("BATCH_CHANGE_WAREHOUSE".equals(taskType)) {// batch transfer logic}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{// Task type unknown system.out.println ("Task type cannot be processed");
        }
Copy the code

So it looks like you’re thinking clearly, you know, the if and else branches are pretty clear, but you don’t feel like your code is bloated, and it’s a hassle to maintain, especially when someone else is taking over, and you don’t even want to read it. At this point, you need to eliminate the if and else in strategic mode and do a simple refactoring!

The strategy pattern

First, abstract the business processor

public abstract class InspectionSolver {

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

    public abstract String[] supports();
}
Copy the code

2. Put the business processor and the types it supports into a container. Map is one of the most common containers in Java

@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; }}Copy the code

At application startup, load all InspectionSolver type processors in the Spring container into InspectionSolverChooser’s map. InspectionSolver (InspectionSolver), so all defined processors must inherit InspectionSolver and be loaded from the Spring container.

3. Define different processors

@Component
public class ChangeWarehouseSolver extends InspectionSolver {

    @Override
    public void solve(Long orderId, Long userId) {
        System.out.println("Order"+orderId+"The batch transfer has begun...");
    }

    @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("Order"+orderId+"The transfer has begun.");
    }

    @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("Order"+orderId+"We're starting to make replacements.");
    }

    @Override
    public String[] supports() {
        returnnew String[]{InspectionConstant.INSPECTION_TASK_TYPE_BATCH_REPLACE_ORDER_GOODS}; }}Copy the code

4. Test classes

@ RunWith (SpringJUnit4ClassRunner. Class) @ SpringBootTest (classes = Application. The class) / / specified spring - the boot startup class public class InspectionTest { @Autowired private InspectionSolverChooser chooser; @Test public voidtest() throws the Exception {/ / prepare data String taskType = InspectionConstant. INSPECTION_TASK_TYPE_BATCH_CHANGE_WAREHOUSE; Long orderId = 12345L; Long userId = 123L; InspectionSolver solver = chooser.choose(taskType);if (solver == null) {
            throw new RuntimeException("The task type is temporarily unprocessable!"); Solver.solve (orderId,userId); solver.solve(orderId,userId); }}Copy the code

In the test class I eliminated a possibly long if else, retrieved different task handler InspectionSolverChooser according to different type, and then called its solve() method for task processing. Different processors call different solve() methods, of course.