找回密码
立即注册
搜索
热搜: Java Python Linux Go
发回帖 发新帖

1378

积分

0

好友

186

主题
发表于 17 小时前 | 查看: 2| 回复: 0

当一个复杂的业务请求需要经过多个处理节点时,例如参数校验、权限检查、业务规则验证等,我们通常会怎么写代码?一个常见的做法是在业务方法中使用大量的 if-else 语句嵌套,或者在代码中硬编码处理步骤的调用顺序。

图片

这种方式有什么问题呢?代码耦合度高、难以维护、不利于扩展和单元测试。当需要新增或调整处理步骤时,往往需要深入修改核心业务逻辑,违反了开闭原则。幸运的是,结合两种经典的设计模式——责任链模式和策略模式,可以优雅地解决这一问题。

一、什么是责任链模式?

责任链模式(Chain of Responsibility Pattern)为请求创建了一个接收者对象的链。它将请求的发送者和接收者解耦,允许多个对象都有机会处理这个请求。每个处理器都包含对下一个处理器的引用。当请求到来时,会沿着链条依次传递,直到有一个处理器处理它为止,或者链条结束。

图片

这种模式非常适合处理多步骤、流水线式的业务场景,如审批流、过滤器链等。

二、什么是策略模式?

策略模式(Strategy Pattern)定义了一系列算法,并将每一个算法封装起来,使它们可以相互替换。策略模式让算法的变化独立于使用算法的客户。

图片

这种模式常用于同一类问题有多种不同解决策略的情况,例如支付方式选择(支付宝、微信、银行卡)、数据验证规则集合等。

三、两种模式如何结合?

我们可以将责任链模式作为宏观框架,用于组织请求的处理流程;而在责任链的某个具体节点(处理器)内部,使用策略模式来管理该节点下多种可选的、可替换的具体行为。这样既能保证处理流程的清晰和可配置性,又能保证每个处理步骤内部逻辑的灵活性与可扩展性。

图片

四、实现思路详解

4.1 定义统一的处理接口

首先我们需要定义一个统一的处理器接口,这是责任链的基础:

// 处理器接口
public interface RequestHandler {
    /**
     * 处理请求
     * @param context 请求上下文
     * @return 是否继续处理
     */
    boolean handle(RequestContext context);

    /**
     * 获取处理器名称
     */
    String getName();
}

4.2 定义请求上下文

为了在处理链中传递数据和状态,我们需要一个上下文对象:

// 请求上下文
public class RequestContext {
    private Map<String, Object> attributes = new HashMap<>();
    private Object requestData;
    private Object responseData;
    private List<String> processLog = new ArrayList<>();

    // getter/setter方法...

    public void addProcessLog(String log) {
        processLog.add(log);
    }
}

4.3 实现责任链接口

接下来实现责任链的核心抽象逻辑,它定义了处理器的链接关系和执行顺序:

// 责任链接口
public abstract class AbstractHandlerChain implements RequestHandler {
    protected RequestHandler nextHandler;

    public void setNextHandler(RequestHandler handler) {
        this.nextHandler = handler;
    }

    @Override
    public boolean handle(RequestContext context) {
        // 当前处理器处理
        boolean result = doHandle(context);

        // 如果处理成功且有下一个处理器,则继续处理
        if (result && nextHandler != null) {
            return nextHandler.handle(context);
        }

        return result;
    }

    // 子类需要实现的具体处理逻辑
    protected abstract boolean doHandle(RequestContext context);
}

4.4 实现具体的处理器

现在我们可以实现各种具体的处理器了,这些处理器通常会使用 Spring 的 @Component 注解进行管理:

// 参数校验处理器
@Component
public class ParameterValidationHandler extends AbstractHandlerChain {

    @Override
    public String getName() {
        return "参数校验处理器";
    }

    @Override
    protected boolean doHandle(RequestContext context) {
        // 获取请求数据
        Object requestData = context.getRequestData();

        // 执行参数校验逻辑
        if (requestData == null) {
            context.addProcessLog("参数为空,校验失败");
            return false;
        }

        // 更多校验逻辑...
        context.addProcessLog("参数校验通过");
        return true;
    }
}

// 权限检查处理器
@Component
public class PermissionCheckHandler extends AbstractHandlerChain {

    @Override
    public String getName() {
        return "权限检查处理器";
    }

    @Override
    protected boolean doHandle(RequestContext context) {
        // 获取用户信息
        String userId = (String) context.getAttribute("userId");

        // 执行权限检查逻辑
        if (!hasPermission(userId)) {
            context.addProcessLog("用户权限不足");
            return false;
        }

        context.addProcessLog("权限检查通过");
        return true;
    }

    private boolean hasPermission(String userId) {
        // 实际的权限检查逻辑
        return true; // 简化示例
    }
}

4.5 策略模式的应用

对于同一类型的处理器,我们可以用策略模式来实现不同的处理策略。以“业务规则校验”这个处理器为例,其内部可以包含多种校验策略:

// 业务规则校验策略接口
public interface BusinessRuleStrategy {
    boolean validate(RequestContext context);
    String getRuleName();
}

// 订单金额校验策略
@Component
public class OrderAmountRuleStrategy implements BusinessRuleStrategy {

    @Override
    public boolean validate(RequestContext context) {
        // 获取订单信息
        OrderInfo orderInfo = (OrderInfo) context.getRequestData();

        // 校验金额是否合理
        if (orderInfo.getAmount().compareTo(BigDecimal.valueOf(100000)) > 0) {
            context.addProcessLog("订单金额过大");
            return false;
        }

        return true;
    }

    @Override
    public String getRuleName() {
        return "订单金额校验";
    }
}

// 库存校验策略
@Component
public class InventoryRuleStrategy implements BusinessRuleStrategy {

    @Override
    public boolean validate(RequestContext context) {
        // 获取商品信息
        ProductInfo productInfo = (ProductInfo) context.getRequestData();

        // 校验库存是否充足
        if (productInfo.getStock() < productInfo.getQuantity()) {
            context.addProcessLog("库存不足");
            return false;
        }

        return true;
    }

    @Override
    public String getRuleName() {
        return "库存校验";
    }
}

// 业务规则校验处理器(使用策略模式)
@Component
public class BusinessRuleHandler extends AbstractHandlerChain {

    @Autowired
    private List<BusinessRuleStrategy> strategies;

    @Override
    public String getName() {
        return "业务规则校验处理器";
    }

    @Override
    protected boolean doHandle(RequestContext context) {
        // 依次执行所有业务规则策略
        for (BusinessRuleStrategy strategy : strategies) {
            if (!strategy.validate(context)) {
                context.addProcessLog("业务规则校验失败: " + strategy.getRuleName());
                return false;
            }
            context.addProcessLog("业务规则校验通过: " + strategy.getRuleName());
        }

        return true;
    }
}

4.6 链的组装和管理

为了让责任链更加灵活和可配置,我们需要一个链的管理器来负责处理器的动态组装。这体现了Spring Boot等框架依赖注入和容器管理的优势。

// 处理链管理器
@Component
public class HandlerChainManager {

    @Autowired
    private List<RequestHandler> handlers;

    // 根据配置组装处理链
    public RequestHandler buildChain(List<String> handlerNames) {
        if (handlerNames == null || handlerNames.isEmpty()) {
            return null;
        }

        RequestHandler head = null;
        RequestHandler current = null;

        for (String handlerName : handlerNames) {
            RequestHandler handler = findHandlerByName(handlerName);
            if (handler != null) {
                if (head == null) {
                    head = handler;
                    current = handler;
                } else {
                    ((AbstractHandlerChain) current).setNextHandler(handler);
                    current = handler;
                }
            }
        }

        return head;
    }

    private RequestHandler findHandlerByName(String name) {
        return handlers.stream()
                .filter(h -> h.getName().equals(name))
                .findFirst()
                .orElse(null);
    }
}

五、使用示例

现在让我们看看在业务服务中如何使用这套机制:

// 服务类
@Service
public class RequestProcessingService {

    @Autowired
    private HandlerChainManager chainManager;

    public ProcessResult processRequest(Object requestData) {
        // 创建请求上下文
        RequestContext context = new RequestContext();
        context.setRequestData(requestData);
        context.setAttribute("userId", getCurrentUserId());

        // 定义处理链顺序(可从配置文件或数据库中读取)
        List<String> handlerSequence = Arrays.asList(
            "参数校验处理器",
            "权限检查处理器",
            "业务规则校验处理器",
            "业务逻辑处理器"
        );

        // 组装处理链
        RequestHandler chain = chainManager.buildChain(handlerSequence);

        // 执行处理
        boolean success = chain != null && chain.handle(context);

        // 返回处理结果
        return ProcessResult.builder()
                .success(success)
                .processLogs(context.getProcessLog())
                .responseData(context.getResponseData())
                .build();
    }

    private String getCurrentUserId() {
        // 获取当前用户ID的逻辑
        return "USER001";
    }
}

5.1 性能优化:加入缓存机制

为了避免每次请求都重新反射和组装处理链,我们可以引入缓存机制:

// 带缓存的处理链管理器
@Component
public class CachedHandlerChainManager extends HandlerChainManager {

    private final Map<String, RequestHandler> chainCache = new ConcurrentHashMap<>();

    public RequestHandler getOrCreateChain(String chainKey, List<String> handlerNames) {
        return chainCache.computeIfAbsent(chainKey, k -> buildChain(handlerNames));
    }
}

5.2 增强健壮性:异常处理

在实际应用中,我们需要确保某个处理器的异常不会导致整个系统崩溃,并能进行适当的日志记录和后续处理。这需要对基础的设计模式抽象进行增强。

// 带异常处理的责任链接口
public abstract class ExceptionSafeHandlerChain extends AbstractHandlerChain {

    @Override
    public boolean handle(RequestContext context) {
        try {
            boolean result = doHandle(context);

            if (result && nextHandler != null) {
                return nextHandler.handle(context);
            }

            return result;
        } catch (Exception e) {
            // 记录异常日志
            context.addProcessLog("处理器执行异常: " + getName() + ", 错误: " + e.getMessage());
            // 根据业务需求决定是否继续执行下一个处理器
            return handleException(e, context);
        }
    }

    protected boolean handleException(Exception e, RequestContext context) {
        // 默认情况下,异常会导致处理链中断
        return false;
    }
}

六、总结

通过将责任链模式与策略模式相结合,我们构建了一个高度解耦、灵活可扩展的请求处理框架。这种架构的优势在于:

  1. 可配置性:处理流程的顺序可以通过配置动态调整,无需修改代码。
  2. 可扩展性:新增处理步骤只需实现新的处理器并注册到 Spring 容器;在策略模式下,新增校验规则也只需新增策略实现类。
  3. 可维护性:每个处理器职责单一,代码逻辑清晰,便于单元测试。
  4. 可观测性:通过请求上下文,可以完整记录请求的处理轨迹和日志,便于调试和监控。

在实际项目中,我们可以根据具体的业务需求来调整这种模式的实现细节,例如增加异步处理支持、优先级调度、监控埋点等,但其核心思想不变:通过合理的抽象和组合,让复杂的业务逻辑变得清晰可控。




上一篇:Go 1.26 新特性解析:new(expr) 表达式如何简化指针创建
下一篇:Go日志模块高并发设计实战:从阻塞优化到源码级性能调优
您需要登录后才可以回帖 登录 | 立即注册

手机版|小黑屋|网站地图|云栈社区 ( 苏ICP备2022046150号-2 )

GMT+8, 2025-12-24 17:26 , Processed in 0.303696 second(s), 39 queries , Gzip On.

Powered by Discuz! X3.5

© 2025-2025 云栈社区.

快速回复 返回顶部 返回列表