责任链模式实践:电商登录校验的演变

写在前面

Hello,我是易元,这篇文章是我学习设计模式时的笔记和心得体会。如果其中有错误,欢迎大家留言指正!

一、初始阶段的直筒式实现

项目初期,登录校验通常只需用户名和密码验证,通常采用硬编码方式完成基础验证:

csharp 复制代码
public boolean validateLogin(String username, String password) {
    if (username == null || username.length() < 5) {
        System.out.println("用户名长度不足");
        return false;
    }
    if (!password.matches("^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)[A-Za-z\d]{8,}$")) {
        System.out.println("密码强度不足");
        return false;
    }
    return "admin".equals(username) && "Secret123".equals(password);
}

但随着用户量增加,安全需求不断升级:

  • 验证码校验:防止脚本攻击
  • IP黑名单拦截:拦截高频攻击IP
  • 设备指纹校验:增强场景化风控

每次新增需求都需在原有方法中插入if判断,代码逐渐臃肿,演变成难以维护的"瑞士军刀式"代码。

二、原始代码的痛点

1. 痛点分析

  • 牵一发而动全身:新增校验逻辑需修改核心方法,易引发连锁BUG。
  • 流程僵化:校验顺序硬编码,无法动态调整。
  • 可读性差:新人接手时难以理解逻辑编排的合理性。

2. 违反的设计原则

传统实现方式演变为:

typescript 复制代码
public boolean validateEverything(...) {
    // 十几个校验逻辑挤在一起
}

已明显违反:

  • 开闭原则:扩展需修改已有代码,而非通过新增类实现。
  • 单一职责原则:一个方法承担过多校验职责。
  • 迪米特法则:模块间耦合度过高。

三、责任链模式重构实战

1. 定义处理流水线

将校验逻辑拆分为独立处理器,形成"质检流水线",每个节点专注单一职责,失败则中断流程,成功则传递至下一节点。

抽象处理器模板
typescript 复制代码
public abstract class Handler {
    private Handler next;
    
    public Handler linkWith(Handler next) {
        this.next = next;
        return next;
    }
    
    public abstract boolean check(LoginRequest request);
    
    protected boolean proceed(LoginRequest request) {
        return next == null || next.check(request);
    }
}
具体实现示例:IP黑名单校验
typescript 复制代码
public class IPHandler extends Handler {
    @Override
    public boolean check(LoginRequest request) {
        if (isBlacklisted(request.getIp())) {
            log.warn("拦截可疑IP: {}", request.getIp());
            return false;
        }
        return proceed(request);
    }
    
    private boolean isBlacklisted(String ip) {
        // 查询IP黑名单库
    }
}

2. 封装请求上下文

将零散参数封装为对象,统一传递上下文:

arduino 复制代码
public class LoginRequest {
    private String username;
    private String password;
    private String captcha;
    private String ip;
    // 其他参数...
}

3. 动态组装执行链

按需组合处理器,灵活控制校验顺序:

java 复制代码
Handler chain = new UsernameHandler()
    .linkWith(new CaptchaHandler())
    .linkWith(new IPHandler())
    .linkWith(new PasswordHandler());

测试用例

java 复制代码
@Test
void testRiskLogin() {
    LoginRequest request = new LoginRequest(
        "admin", "WrongPass123", "captcha", "192.168.10.100"
    );
    boolean result = chain.check(request);
    assertFalse(result);
}
执行结果
css 复制代码
[校验] 用户名格式合法  
[校验] 验证码校验通过  
[风控拦截] 高风险IP  
登录结果:失败  

四、Spring Security的启示

Spring Security的过滤器链是责任链模式的经典实现

核心过滤器链逻辑(简化)
typescript 复制代码
public class FilterChainProxy implements Filter {
    private List<SecurityFilterChain> chains;

    public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) {
        for (SecurityFilterChain f : chains) {
            f.doFilter(req, res, chain); // 责任链传递
        }
    }
}
具体过滤器实现
typescript 复制代码
public class UsernamePasswordAuthenticationFilter implements Filter {
    public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) {
        // 认证逻辑处理
        chain.doFilter(req, res); // 传递到下一过滤器
    }
}

模式映射

  • HandlerFilter 接口
  • linkWith() → Spring通过List维护过滤器顺序
  • check()doFilter() 方法

五、长话短说

1. 适用场景

  • 需要动态组合处理流程时
  • 存在多个候选处理逻辑时
  • 需解耦请求方与处理方时

2. 实现四步法

  1. 定义抽象接口:约定处理与链式传递机制。
  2. 实现处理节点:每个类专注单一校验逻辑。
  3. 组装执行链:按需组合处理器。
  4. 封装上下文:统一传递参数。

3. 避坑指南

  • 避免长链:节点超过10个时建议拆分。
  • 性能敏感场景慎用:链式调用存在轻微性能损耗。
  • 统一异常处理:明确中断、继续等策略。
  • 防循环引用:链配置需严格检测。

4. 扩展技巧

  • 结合策略模式:动态替换处理器实现。
  • 添加监控节点:记录各节点执行耗时。
  • 优先级控制 :通过@Order注解调整顺序。
相关推荐
文心快码BaiduComate14 小时前
我用文心快码Spec 模式搓了个“pre作弊器”,妈妈再也不用担心我开会忘词了(附源码)
前端·后端·程序员
aiopencode14 小时前
iOS 性能监控 运行时指标与系统行为的多工具协同方案
后端
E***U94514 小时前
从新手到入门:如何判断自己是否真的学会了 Spring Boot
数据库·spring boot·后端
招风的黑耳14 小时前
智慧养老项目:当SpringBoot遇到硬件,如何优雅地处理异常与状态管理?
java·spring boot·后端
回家路上绕了弯15 小时前
分布式锁原理深度解析:从理论到实践
分布式·后端
磊磊磊磊磊15 小时前
用AI做了个排版工具,分享一下如何高效省钱地用AI!
前端·后端·react.js
hgz071015 小时前
Spring Boot Starter机制
java·spring boot·后端
daxiang1209220515 小时前
Spring boot服务启动报错 java.lang.StackOverflowError 原因分析
java·spring boot·后端
我家领养了个白胖胖15 小时前
极简集成大模型!Spring AI Alibaba ChatClient 快速上手指南
java·后端·ai编程
一代明君Kevin学长15 小时前
快速自定义一个带进度监控的文件资源类
java·前端·后端·python·文件上传·文件服务·文件流