写在前面
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); // 传递到下一过滤器
}
}
模式映射:
Handler
→Filter
接口linkWith()
→ Spring通过List
维护过滤器顺序check()
→doFilter()
方法
五、长话短说
1. 适用场景
- 需要动态组合处理流程时
- 存在多个候选处理逻辑时
- 需解耦请求方与处理方时
2. 实现四步法
- 定义抽象接口:约定处理与链式传递机制。
- 实现处理节点:每个类专注单一校验逻辑。
- 组装执行链:按需组合处理器。
- 封装上下文:统一传递参数。
3. 避坑指南
- 避免长链:节点超过10个时建议拆分。
- 性能敏感场景慎用:链式调用存在轻微性能损耗。
- 统一异常处理:明确中断、继续等策略。
- 防循环引用:链配置需严格检测。
4. 扩展技巧
- 结合策略模式:动态替换处理器实现。
- 添加监控节点:记录各节点执行耗时。
- 优先级控制:通过
@Order
注解调整顺序。
评论记录:
回复评论: