Eliminate Complex if‑else Chains with Strategy and Chain‑of‑Responsibility Patterns in Java

This article demonstrates how to replace cumbersome if‑else or switch‑case logic in Java receipt processing with clean, extensible solutions using the Strategy pattern combined with a Map dictionary, and the Chain of Responsibility pattern, while preserving the Open/Closed principle.

Java Interview Crash Guide
Java Interview Crash Guide
Java Interview Crash Guide
Eliminate Complex if‑else Chains with Strategy and Chain‑of‑Responsibility Patterns in Java

Lu Xun once said that high‑quality code should be written in the simplest way. Simple business logic can use if‑else or switch‑case, but as the logic grows, these structures become redundant and hard to maintain; design patterns can make the code more elegant.

In the logistics domain, EDI messages (XML files) are sent and a receipt is received indicating the message's status. Common receipt types include MT1101, MT2101, MT4101, MT8104, MT8105, and MT9999. The article uses receipt handling as a demo case.

1 Traditional if‑else branching

@Data
public class Receipt {
    /**
     * Receipt information
     */
    String message;
    /**
     * Receipt type (MT1101, MT2101, MT4101, MT8104, MT8105, MT9999)
     */
    String type;
}
public class ReceiptBuilder {
    public static List<Receipt> generateReceiptList() {
        // Simulate a bunch of receipt objects
        List<Receipt> receiptList = new ArrayList<>();
        receiptList.add(new Receipt("我是MT2101回执喔", "MT2101"));
        receiptList.add(new Receipt("我是MT1101回执喔", "MT1101"));
        receiptList.add(new Receipt("我是MT8104回执喔", "MT8104"));
        receiptList.add(new Receipt("我是MT9999回执喔", "MT9999"));
        //......
        return receiptList;
    }
}

Processing each receipt with a long if‑else chain quickly violates the Open/Closed principle because every new receipt type requires modifying the chain.

2 Strategy pattern + Map dictionary

The Strategy pattern encapsulates algorithms behind a common interface, allowing the client to select a strategy without hard‑coded if‑else logic. A simple factory can retrieve the appropriate strategy.

public interface IReceiptHandleStrategy {
    void handleReceipt(Receipt receipt);
}
public class Mt2101ReceiptHandleStrategy implements IReceiptHandleStrategy {
    @Override
    public void handleReceipt(Receipt receipt) {
        System.out.println("解析报文MT2101:" + receipt.getMessage());
    }
}

public class Mt1101ReceiptHandleStrategy implements IReceiptHandleStrategy {
    @Override
    public void handleReceipt(Receipt receipt) {
        System.out.println("解析报文MT1101:" + receipt.getMessage());
    }
}
public class ReceiptStrategyContext {
    private IReceiptHandleStrategy receiptHandleStrategy;
    public void setReceiptHandleStrategy(IReceiptHandleStrategy receiptHandleStrategy) {
        this.receiptHandleStrategy = receiptHandleStrategy;
    }
    public void handleReceipt(Receipt receipt) {
        if (receiptHandleStrategy != null) {
            receiptHandleStrategy.handleReceipt(receipt);
        }
    }
}
public class ReceiptHandleStrategyFactory {
    private static Map<String, IReceiptHandleStrategy> receiptHandleStrategyMap = new HashMap<>();
    private ReceiptHandleStrategyFactory() {
        receiptHandleStrategyMap.put("MT2101", new Mt2101ReceiptHandleStrategy());
        receiptHandleStrategyMap.put("MT8104", new Mt8104ReceiptHandleStrategy());
    }
    public static IReceiptHandleStrategy getReceiptHandleStrategy(String receiptType) {
        return receiptHandleStrategyMap.get(receiptType);
    }
}

Clients obtain a strategy from the factory, set it in the context, and invoke the handling method, eliminating the if‑else chain.

3 Chain of Responsibility pattern

The Chain of Responsibility links handlers so that a request traverses the chain until a handler processes it. The client does not know which handler will act.

public interface IReceiptHandler {
    void handleReceipt(Receipt receipt, IReceiptHandleChain handleChain);
}
public interface IReceiptHandleChain {
    void handleReceipt(Receipt receipt);
}
public class ReceiptHandleChain implements IReceiptHandleChain {
    private int index = 0;
    private static List<IReceiptHandler> receiptHandlerList;
    static {
        receiptHandlerList = ReceiptHandlerContainer.getReceiptHandlerList();
    }
    @Override
    public void handleReceipt(Receipt receipt) {
        if (receiptHandlerList != null && !receiptHandlerList.isEmpty()) {
            if (index != receiptHandlerList.size()) {
                IReceiptHandler receiptHandler = receiptHandlerList.get(index++);
                receiptHandler.handleReceipt(receipt, this);
            }
        }
    }
}
public class Mt2101ReceiptHandler implements IReceiptHandler {
    @Override
    public void handleReceipt(Receipt receipt, IReceiptHandleChain handleChain) {
        if (StringUtils.equals("MT2101", receipt.getType())) {
            System.out.println("解析报文MT2101:" + receipt.getMessage());
        } else {
            handleChain.handleReceipt(receipt);
        }
    }
}

Handlers that cannot process the receipt delegate to the next handler via the chain.

public class ReceiptHandlerContainer {
    public static List<IReceiptHandler> getReceiptHandlerList() {
        List<IReceiptHandler> receiptHandlerList = new ArrayList<>();
        receiptHandlerList.add(new Mt2101ReceiptHandler());
        receiptHandlerList.add(new Mt8104ReceiptHandler());
        return receiptHandlerList;
    }
}

Using reflection, the container can automatically discover all implementations of IReceiptHandler, making the solution fully compliant with the Open/Closed principle.

4 Strategy pattern + Annotation

By defining a custom annotation on each handler class and scanning the classpath, the framework can build the strategy map without manual registration, achieving the same extensibility as the previous approach.

5 Summary

For simple business logic, plain if‑else or switch statements are clear and efficient. When the number of branches grows, applying patterns such as Strategy, Chain of Responsibility, or annotation‑driven factories makes the code cleaner and easier to maintain, though it also increases the number of classes. Proper analysis is essential to avoid over‑engineering.

Chain of ResponsibilityJavastrategy patternrefactoring
Java Interview Crash Guide
Written by

Java Interview Crash Guide

Dedicated to sharing Java interview Q&A; follow and reply "java" to receive a free premium Java interview guide.

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.