Backend Development 16 min read

Understanding the Chain of Responsibility Pattern and Its Combination with Strategy Pattern in Java

This article explains the Chain of Responsibility design pattern, its core concepts, characteristics, and problems it solves, then demonstrates how to combine it with the Strategy pattern through detailed Java code examples that illustrate a product‑up‑shelf validation workflow and a generic request‑handling scenario.

Selected Java Interview Questions
Selected Java Interview Questions
Selected Java Interview Questions
Understanding the Chain of Responsibility Pattern and Its Combination with Strategy Pattern in Java

What is the Chain of Responsibility Pattern?

The Chain of Responsibility Pattern ( Chain of Responsibility Pattern ) is a behavioral design pattern that allows a request to be passed along a chain of handlers until one of them processes it, decoupling the sender from the receiver.

Core idea: decouple request sender and receiver by forming a chain of objects that pass the request along until it is handled.

Characteristics of the Pattern

Decouples request sender and handler: enhances flexibility and extensibility.

Dynamic composition of logic: chain structure can be changed at runtime.

Single responsibility: each handler focuses on one validation task.

Extensibility: new handlers can be added without modifying existing code.

Clear flow: organizes validation logic for better readability.

Combining Chain of Responsibility with Strategy Pattern

Role of Chain of Responsibility

Used for dynamic request processing by linking multiple validation steps.

Role of Strategy Pattern

Encapsulates a set of algorithms, allowing dynamic selection at runtime.

Combined, the chain controls request flow while each handler delegates its specific logic to a strategy, enabling flexible and modular processing.

Problems Solved by the Pattern

High coupling: separates request sender from handlers.

Complex conditional logic: avoids excessive if‑else or switch statements.

Lack of flexibility: dynamic chain composition adjusts processing logic.

Code duplication: each handler addresses only its concern.

Code Analysis – Product Up‑Shelf Scenario

1. Define the abstract chain interface

public interface MerchantAdminAbstractChainHandler
extends Ordered {
    void handler(T requestParam);
    String mark();
    default int getOrder() { return Ordered.LOWEST_PRECEDENCE; }
}

2. Define chain identifier enum

public enum ChainBizMarkEnum {
    MERCHANT_ADMIN_CREATE_PRODUCT_TEMPLATE_KEY,
    MERCHANT_ADMIN_PRODUCT_UPSHELF_KEY; // new product up‑shelf chain identifier
}

3. Implement the chain context

public final class MerchantAdminChainContext
implements ApplicationContextAware, CommandLineRunner {
    private ApplicationContext applicationContext;
    private final Map
> abstractChainHandlerContainer = new HashMap<>();
    public void handler(String mark, T requestObj) {
        List
handlers = abstractChainHandlerContainer.get(mark);
        if (CollectionUtils.isEmpty(handlers)) {
            throw new RuntimeException(String.format("[%s] Chain of Responsibility ID is undefined.", mark));
        }
        handlers.forEach(each -> each.handler(requestObj));
    }
    @Override
    public void run(String... args) throws Exception {
        Map
chainFilterMap = applicationContext.getBeansOfType(MerchantAdminAbstractChainHandler.class);
        chainFilterMap.forEach((beanName, bean) -> {
            List
list = abstractChainHandlerContainer.getOrDefault(bean.mark(), new ArrayList<>());
            list.add(bean);
            abstractChainHandlerContainer.put(bean.mark(), list);
        });
        abstractChainHandlerContainer.forEach((mark, chainHandlers) -> chainHandlers.sort(Comparator.comparing(Ordered::getOrder)));
    }
    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        this.applicationContext = applicationContext;
    }
}

4. Implement concrete handlers

@Component
public class ProductInfoNotNullChainFilter implements MerchantAdminAbstractChainHandler
{
    @Override
    public void handler(ProductUpShelfReqDTO requestParam) {
        if (StringUtils.isEmpty(requestParam.getProductName())) {
            throw new RuntimeException("商品名称不能为空!");
        }
        if (requestParam.getPrice() == null || requestParam.getPrice() <= 0) {
            throw new RuntimeException("商品价格必须大于0!");
        }
        System.out.println("商品信息非空校验通过");
    }
    @Override
    public int getOrder() { return 1; }
    @Override
    public String mark() { return ChainBizMarkEnum.MERCHANT_ADMIN_PRODUCT_UPSHELF_KEY.name(); }
}

@Component
public class ProductInventoryCheckChainFilter implements MerchantAdminAbstractChainHandler
{
    @Override
    public void handler(ProductUpShelfReqDTO requestParam) {
        if (requestParam.getStock() <= 0) {
            throw new RuntimeException("商品库存不足,无法上架!");
        }
        System.out.println("商品库存校验通过");
    }
    @Override
    public int getOrder() { return 2; }
    @Override
    public String mark() { return ChainBizMarkEnum.MERCHANT_ADMIN_PRODUCT_UPSHELF_KEY.name(); }
}

5. Service layer invoking the chain

@Service
@RequiredArgsConstructor
public class ProductServiceImpl {
    private final MerchantAdminChainContext
merchantAdminChainContext;
    public void upShelfProduct(ProductUpShelfReqDTO requestParam) {
        merchantAdminChainContext.handler(ChainBizMarkEnum.MERCHANT_ADMIN_PRODUCT_UPSHELF_KEY.name(), requestParam);
        System.out.println("商品上架逻辑开始执行...");
        // further business logic
    }
}

Combining Chain of Responsibility with Strategy Pattern (Generic Example)

1. Define handler interface

public interface RequestHandler {
    void setNextHandler(RequestHandler nextHandler);
    void handleRequest(UserRequest request);
}

2. Define request class

public class UserRequest {
    private String userType;
    private String requestContent;
    public UserRequest(String userType, String requestContent) { this.userType = userType; this.requestContent = requestContent; }
    public String getUserType() { return userType; }
    public String getRequestContent() { return requestContent; }
}

3. Define strategy interface and implementations

public interface RequestStrategy { void process(UserRequest request); }
public class BasicUserStrategy implements RequestStrategy { @Override public void process(UserRequest request) { System.out.println("普通用户的请求正在处理:" + request.getRequestContent()); } }
public class AdminUserStrategy implements RequestStrategy { @Override public void process(UserRequest request) { System.out.println("管理员的请求正在处理:" + request.getRequestContent()); } }
public class SuperAdminStrategy implements RequestStrategy { @Override public void process(UserRequest request) { System.out.println("高级管理员的请求正在处理:" + request.getRequestContent()); } }

4. Implement concrete handler that uses a strategy

public class RequestHandlerImpl implements RequestHandler {
    private RequestStrategy strategy;
    private RequestHandler nextHandler;
    public RequestHandlerImpl(RequestStrategy strategy) { this.strategy = strategy; }
    @Override public void setNextHandler(RequestHandler nextHandler) { this.nextHandler = nextHandler; }
    @Override public void handleRequest(UserRequest request) {
        strategy.process(request);
        if (nextHandler != null) { nextHandler.handleRequest(request); }
    }
}

5. Test the combined chain and strategy

public class ChainStrategyExample {
    public static void main(String[] args) {
        RequestStrategy basicStrategy = new BasicUserStrategy();
        RequestStrategy adminStrategy = new AdminUserStrategy();
        RequestStrategy superAdminStrategy = new SuperAdminStrategy();
        RequestHandler basicHandler = new RequestHandlerImpl(basicStrategy);
        RequestHandler adminHandler = new RequestHandlerImpl(adminStrategy);
        RequestHandler superAdminHandler = new RequestHandlerImpl(superAdminStrategy);
        basicHandler.setNextHandler(adminHandler);
        adminHandler.setNextHandler(superAdminHandler);
        UserRequest basicRequest = new UserRequest("普通用户", "请求访问资源 A");
        UserRequest adminRequest = new UserRequest("管理员", "请求修改资源 B");
        UserRequest superAdminRequest = new UserRequest("高级管理员", "请求删除资源 C");
        System.out.println("处理普通用户请求:");
        basicHandler.handleRequest(basicRequest);
        System.out.println("\n处理管理员请求:");
        adminHandler.handleRequest(adminRequest);
        System.out.println("\n处理高级管理员请求:");
        superAdminHandler.handleRequest(superAdminRequest);
    }
}

Combining the Chain of Responsibility with the Strategy pattern separates flow control from business logic, enhances flexibility, and makes the system easier to extend and maintain.

BackendChain of ResponsibilityJavastrategy patternDesign Pattern
Selected Java Interview Questions
Written by

Selected Java Interview Questions

A professional Java tech channel sharing common knowledge to help developers fill gaps. Follow us!

0 followers
Reader feedback

How this landed with the community

login 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.