稀土掘金技术社区 01月19日
Java 实现责任链模式 + 策略模式:优雅处理多级请求的方式
index_new5.html
../../../zaker_core/zaker_tpl_static/wap/tpl_guoji1.html

 

本文深入探讨了责任链模式在后端开发中的应用,并结合策略模式进行了扩展。责任链模式通过解耦请求的发送者和接收者,允许请求沿着处理链传递,直至被处理。文章详细阐述了责任链模式的核心思想、特点以及如何解决耦合过高、复杂的多条件判断等问题。此外,文章还通过商品上架逻辑的实例,展示了如何利用责任链模式实现多重校验,以及如何与策略模式结合,实现更灵活的请求处理。最后,文章给出了一个完整的Java示例,演示了责任链模式和策略模式的结合使用,进一步加深了对这两种设计模式的理解。

🔗责任链模式的核心思想是将请求的发送者与接收者解耦,通过让多个对象组成一条链,使得请求沿着链传递,直到被处理。这提高了系统的灵活性和可扩展性。

🛠️责任链模式的特点包括:解耦请求发出者和处理者,动态组合处理逻辑,职责单一,可扩展性强,流程清晰。每个处理器负责单一的验证职责,符合单一职责原则。

💡责任链模式与策略模式结合使用,可以实现既动态构建责任链,又灵活应用不同策略来处理请求的需求。责任链负责串联和传递请求,而策略模式定义了每个处理器的具体处理逻辑。

🛒文章通过商品上架逻辑的实例,展示了如何利用责任链模式实现多重校验,包括商品信息和库存信息的校验。每个校验逻辑都封装在一个独立的处理器中,使得代码结构更加清晰。

💻文章还提供了一个完整的Java示例,演示了责任链模式和策略模式的结合使用,模拟了用户请求的审核流程,包括普通用户、管理员和高级管理员的审批,以及不同策略的处理逻辑。

原创 后端出路在何方 2025-01-17 08:30 重庆

点击关注公众号,“技术干货” 及时达!

什么是责任链模式?

「责任链模式(Chain of Responsibility Pattern)」 是一种行为设计模式,它允许将请求沿着一个处理链传递,直到链中的某个对象处理它。这样,发送者无需知道哪个对象将处理请求,所有的处理对象都可以尝试处理请求或将请求传递给链上的下一个对象。

「核心思想」:将请求的发送者与接收者解耦,通过让多个对象组成一条链,使得请求沿着链传递,直到被处理。

责任链模式的特点

    「解耦请求发出者和处理者」:请求的发送者不需要知道具体的处理者是谁,增强了系统的灵活性和扩展性。

    「动态组合处理逻辑」:可以根据需要动态改变链的结构,添加或移除处理者。

    「职责单一」:责任链模式可以将每个验证逻辑封装到一个独立的处理器中,每个处理器负责单一的验证职责,符合单一职责原则。

    「可扩展性」: 增加新的验证逻辑时,处理者只需继承一个统一的接口,并添加新的处理器,而不需要修改现有的代码。

    「清晰的流程」: 将所有验证逻辑组织在一起,使得代码结构更加清晰,易于理解。

责任链模式和策略模式结合的意义

结合两者:

责任链模式解决的问题

    「耦合过高」:将请求的处理者从请求的发送者中解耦,使得处理者可以独立扩展或变更。

    「复杂的多条件判断」:避免在代码中使用过多 if-elseswitch-case 语句。

    「灵活性不足」:通过链的动态组合可以轻松调整请求的传递逻辑或插入新的处理者。

    「代码重复」:每个处理者只专注于处理它关心的部分,减少重复代码。

代码中的责任链模式解析

场景 1:商品上架逻辑(多重校验)

实现一个类似的场景——商品上架逻辑(如校验商品信息、库存信息等),可以按照以下步骤实现:

    定义责任链抽象接口

public interface MerchantAdminAbstractChainHandler<T> extends Ordered {
/** * 执行责任链逻辑 * * @param requestParam 责任链执行入参 */ void handler(T requestParam);
/** * @return 责任链组件标识 */ String mark();}

    定义商品上架的责任链标识:

public enum ChainBizMarkEnum {    MERCHANT_ADMIN_CREATE_PRODUCT_TEMPLATE_KEY,    MERCHANT_ADMIN_PRODUCT_UPSHELF_KEY; // 新增商品上架责任链标识}

    定义每个处理器的通用行为:

@Componentpublic final class MerchantAdminChainContext<T> implements ApplicationContextAware, CommandLineRunner {    /**     * 应用上下文,通过Spring IOC获取Bean实例     */    private ApplicationContext applicationContext;
/** * 保存商品上架责任链实现类 * <p> * Key:{@link MerchantAdminAbstractChainHandler#mark()} * Val:{@link MerchantAdminAbstractChainHandler} 一组责任链实现 Spring Bean 集合 * <p> * 比如有一个商品上架模板创建责任链,实例如下: * Key:MERCHANT_ADMIN_CREATE_PRODUCT_TEMPLATE_KEY * Val: * - 验证商品信息基本参数是否必填 —— 执行器 {@link ProductInfoNotNullChainFilter} * - 验证商品库存 —— 执行器 {@link ProductInventoryCheckChainFilter} */ private final Map<String, List<MerchantAdminAbstractChainHandler>> abstractChainHandlerContainer = new HashMap<>();
/** * 责任链组件执行 * @param mark 责任链组件标识 * @param requestObj 请求参数 */ public void handler(String mark,T requestObj){ // 根据 mark 标识从责任链容器中获取一组责任链实现 Bean 集合 List<MerchantAdminAbstractChainHandler> abstractChainHandlers = abstractChainHandlerContainer.get(mark); if (CollectionUtils.isEmpty(abstractChainHandlers)) { throw new RuntimeException(String.format("[%s] Chain of Responsibility ID is undefined.", mark)); } abstractChainHandlers.forEach(each -> each.handler(requestObj)); }
/** * 执行方法,接收可变参数 * 本方法主要用于初始化和处理商品上架抽象责任链容器 * 它从Spring容器中获取所有MerchantAdminAbstractChainHandler类型的Bean, * 并根据它们的mark进行分类和排序,以便后续处理 * * @param args 可变参数,可能包含方法运行所需的额外信息 * @throws Exception 如果方法执行过程中遇到错误,抛出异常 */ @Override public void run(String... args) throws Exception { // 从 Spring IOC 容器中获取指定接口 Spring Bean 集合 Map<String, MerchantAdminAbstractChainHandler> chainFilterMap = applicationContext.getBeansOfType(MerchantAdminAbstractChainHandler.class); // 遍历所有获取到的Bean,并将它们根据mark分类存入抽象责任链容器中 chainFilterMap.forEach((beanName, bean) -> { // 判断 Mark 是否已经存在抽象责任链容器中,如果已经存在直接向集合新增;如果不存在,创建 Mark 和对应的集合 List<MerchantAdminAbstractChainHandler> abstractChainHandlers = abstractChainHandlerContainer.getOrDefault(bean.mark(), new ArrayList<>()); abstractChainHandlers.add(bean); abstractChainHandlerContainer.put(bean.mark(), abstractChainHandlers); }); // 遍历抽象责任链容器,对每个 Mark 对应的责任链实现类集合进行排序 abstractChainHandlerContainer.forEach((mark, chainHandlers) -> { // 对每个 Mark 对应的责任链实现类集合进行排序,优先级小的在前 chainHandlers.sort(Comparator.comparing(Ordered::getOrder)); }); }
@Override public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { this.applicationContext = applicationContext; }}

    定义商品上架的责任链处理器:

@Componentpublic class ProductInfoNotNullChainFilter implements MerchantAdminAbstractChainHandler<ProductUpShelfReqDTO> {    @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(); }}
@Componentpublic class ProductInventoryCheckChainFilter implements MerchantAdminAbstractChainHandler<ProductUpShelfReqDTO> { @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(); }}

    调用责任链进行处理:

@Service@RequiredArgsConstructorpublic class ProductServiceImpl {    private final MerchantAdminChainContext<ProductUpShelfReqDTO> merchantAdminChainContext;
public void upShelfProduct(ProductUpShelfReqDTO requestParam) { // 调用责任链进行校验 merchantAdminChainContext.handler( ChainBizMarkEnum.MERCHANT_ADMIN_PRODUCT_UPSHELF_KEY.name(), requestParam ); System.out.println("商品上架逻辑开始执行..."); // 后续的商品上架业务逻辑 }}

上述代码实现了一个基于 「责任链模式」 的电商系统,主要用于处理复杂的业务逻辑,如商品上架模板的创建。这种模式的设计使得每个业务逻辑通过一个独立的处理器(Handler)进行处理,并将这些处理器串联成一个链,通过统一的入口执行每一步处理操作。

代码的组成部分与职责解析

「(1) 责任链抽象接口:MerchantAdminAbstractChainHandler

「(2) 抽象处理器接口:MerchantAdminAbstractChainHandler

import org.springframework.core.Ordered;
/** * 商家上架责任链处理器抽象接口 * * @param <T> 处理参数的泛型类型(比如请求参数) */public interface MerchantAdminAbstractChainHandler<T> extends Ordered {
/** * 执行责任链的具体逻辑 * * @param requestParam 责任链执行的入参 */ void handler(T requestParam);
/** * 获取责任链处理器的标识(mark) * * 每个处理器所属的责任链标识需要唯一,用于区分不同的责任链。 * * @return 责任链组件标识 */ String mark();
/** * 获取责任链执行顺序 * * Spring 的 {@link Ordered} 接口方法,数值越小优先级越高。 * 默认返回 `Ordered.LOWEST_PRECEDENCE`,表示优先级最低。 * * @return 处理器的执行顺序。 */ @Override default int getOrder() { return Ordered.LOWEST_PRECEDENCE; }}

「(2) 责任链上下文:MerchantAdminChainContext

「(3) 业务服务层:ProductInventoryCheckChainFilter

责任链的执行流程

通过 MerchantAdminChainContext,上述两个处理器会被自动扫描并加载到责任链中。运行时,根据 mark()getOrder() 的值,系统自动按顺序执行它们。

Java 实现责任链模式 + 策略模式

以下是实现一个责任链 + 策略模式的完整 Java 示例。

「场景」:模拟用户请求的审核流程(如普通用户审批、管理员审批、高级管理员审批),并结合不同策略处理请求。

1. 定义处理请求的接口

// 抽象处理者接口public interface RequestHandler {    // 设置下一个处理者    void setNextHandler(RequestHandler nextHandler);        // 处理请求的方法    void handleRequest(UserRequest request);}

2. 定义用户请求类

// 请求类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. 定义不同的策略(处理逻辑)

// 策略接口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. 实现责任链模式的处理者

// 具体处理者,结合策略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. 测试责任链 + 策略模式

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

为何责任链模式和策略模式结合使用?

    「责任链控制流程,策略定义处理逻辑」

「职责分离」

「增强灵活性和可扩展性」

通过责任链模式与策略模式的结合,可以应对复杂的处理流程和多变的业务需求,同时保持代码的简洁与高内聚的设计结构。

点击关注公众号,“技术干货” 及时达!

阅读原文

跳转微信打开

Fish AI Reader

Fish AI Reader

AI辅助创作,多种专业模板,深度分析,高质量内容生成。从观点提取到深度思考,FishAI为您提供全方位的创作支持。新版本引入自定义参数,让您的创作更加个性化和精准。

FishAI

FishAI

鱼阅,AI 时代的下一个智能信息助手,助你摆脱信息焦虑

联系邮箱 441953276@qq.com

相关标签

责任链模式 策略模式 设计模式 后端开发 Java
相关文章