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.
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.
Selected Java Interview Questions
A professional Java tech channel sharing common knowledge to help developers fill gaps. Follow us!
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.