责任链模式 | 优化请求数据校验 - 附带改造案例

先来展示一个传统校验方式

以购票请求校验为例:

public class TicketServiceImpl implements TicketService {
    
    @Autowired
    //....Mapper层


    public void Query(TicketRequest request) {
        // 基础校验
        if (request.getUserId() == null) {
            throw new ValidationException("用户ID不能为空");
        }
        if (StringUtils.isEmpty(request.getTrainNumber())) {
            throw new ValidationException("车次不能为空");
        }
        
        // 查询专用校验
        if (request.getDepartureDate() == null) {
            throw new ValidationException("出发日期不能为空");
        }
        if (request.getDepartureDate().isBefore(LocalDate.now())) {
            throw new ValidationException("不能查询历史日期车票");
        }

        ....查询逻辑

    }
    
    public void Order(OrderRequest request) {
        // 基础校验重复代码...
        if (request.getUserId() == null) {
            throw new ValidationException("用户ID不能为空");
        }
        
        // 下单专用校验
        if (request.getSeats() == null || request.getSeats().isEmpty()) {
            throw new ValidationException("至少选择一个座位");
        }
        if (request.getTotalPrice().compareTo(BigDecimal.ZERO) <= 0) {
            throw new ValidationException("金额必须大于0");
        }

        ....下单逻辑

    }
}

这种校验模式有几大问题:

  • 校验逻辑重复(如用户ID校验)
  • 业务耦合度高
  • 难以扩展新校验规则

责任链模式改造

1、改造完的Service

@Service
public class TicketServiceImpl implements TicketService {

    @Autowired
    private ValidationService validationService;
    
    public Ticket queryTickets(QueryRequest request) {
        validator.validate(request); // 自动走基础+查询校验
        // 查询逻辑...
    }
    
    public void createOrder(OrderRequest request) {
        validator.validate(request); // 自动走基础+订单校验
        // 下单逻辑...
    }

}

2、请求对象结构

// 基础请求
public class TicketRequest {
    private Long userId;
    private String trainNumber;
    // getters/setters...
}

// 查询请求
public class QueryRequest extends TicketRequest {
    private LocalDate departureDate;
    // 扩展字段...
}

// 订单请求
public class OrderRequest extends TicketRequest {
    private List<String> seats;
    private BigDecimal totalPrice;
    // 扩展字段...
}

3、Validation层(校验层)        

3.1、校验服务接口Service

public interface ValidationService {
    void validateQuery(QueryRequest request);
    void validateOrder(OrderRequest request);
}

3.2、校验服务实现ServiceImpl

@Service
public class ValidationServiceImpl implements ValidationService {
    
    @Autowired
    @Qualifier("queryValidatorChain")
    private ValidationHandler<QueryRequest> queryValidator;
    
    @Autowired
    @Qualifier("orderValidatorChain")
    private ValidationHandler<OrderRequest> orderValidator;
    
    @Override
    public void validateQuery(QueryRequest request) {
        queryValidator.handle(request);
    }
    
    @Override
    public void validateOrder(OrderRequest request) {
        orderValidator.handle(request);
    }
}

4、Validator配置层

校验器配置类

@Configuration
public class ValidatorConfig {
    
    @Bean
    @Qualifier("basicValidator")
    public BasicValidator basicValidator() {
        return new BasicValidator();
    }
    
    @Bean
    @Qualifier("queryValidator")
    public QueryValidator queryValidator() {
        return new QueryValidator();
    }
    
    @Bean
    @Qualifier("orderValidator")
    public OrderValidator orderValidator() {
        return new OrderValidator();
    }
    
    @Bean
    @Qualifier("queryValidatorChain")
    public ValidationHandler<QueryRequest> queryValidatorChain(
            @Qualifier("basicValidator") BasicValidator basic,
            @Qualifier("queryValidator") QueryValidator query) {
        basic.setNext(query);
        return basic;
    }
    
    @Bean
    @Qualifier("orderValidatorChain")
    public ValidationHandler<OrderRequest> orderValidatorChain(
            @Qualifier("basicValidator") BasicValidator basic,
            @Qualifier("orderValidator") OrderValidator order) {
        basic.setNext(order);
        return basic;
    }
}

5、Validator实现层

5.1、抽象验证处理器

public abstract class AbstractValidationHandler<T> implements ValidationHandler<T> {
    private ValidationHandler<T> next;
    
    @Override
    public void setNext(ValidationHandler<T> next) {
        this.next = next;
    }
    
    @Override
    public void handle(T request) throws ValidationException {
        doValidate(request);
        if (next != null) {
            next.handle(request);
        }
    }
    
    protected abstract void doValidate(T request) throws ValidationException;
}

5.2、具体验证器实现

@Component
public class BasicValidator extends AbstractValidationHandler<TicketRequest> {
    @Override
    protected void doValidate(TicketRequest request) throws ValidationException {
        if (request.getUserId() == null) {
            throw new ValidationException("USER_ID_REQUIRED", "用户ID不能为空");
        }
        if (StringUtils.isEmpty(request.getTrainNumber())) {
            throw new ValidationException("TRAIN_NUMBER_REQUIRED", "车次不能为空");
        }
    }
}

@Component
public class QueryValidator extends AbstractValidationHandler<QueryRequest> {
    @Override
    protected void doValidate(QueryRequest request) throws ValidationException {
        if (request.getDepartureDate() == null) {
            throw new ValidationException("DEPARTURE_DATE_REQUIRED", "出发日期必须指定");
        }
        if (request.getDepartureDate().isBefore(LocalDate.now())) {
            throw new ValidationException("INVALID_DEPARTURE_DATE", "不能查询历史日期车票");
        }
    }
}

@Component
public class OrderValidator extends AbstractValidationHandler<OrderRequest> {
    @Override
    protected void doValidate(OrderRequest request) throws ValidationException {
        if (request.getSeats() == null || request.getSeats().isEmpty()) {
            throw new ValidationException("SEAT_SELECTION_REQUIRED", "至少选择一个座位");
        }
        if (request.getSeats().size() > 5) {
            throw new ValidationException("MAX_SEAT_LIMIT", "单次最多购买5张票");
        }
    }
}

改造优势对比​

维度传统方式责任链模式
​代码复用​重复校验逻辑共用基础校验链
​扩展性​需修改原类添加新Handler即可
​可读性​方法臃肿每个校验器职责单一
​维护性​牵一发而动全身独立修改不影响其他
​灵活性​固定校验顺序动态调整链条顺序

典型场景​​:

当系统需要支持新的校验规则(如疫情防控期间限制购票地区),责任链模式只需新增一个EpidemicValidator即可,而传统方式需要修改所有校验方法。

示例

新增疫情校验器:

@Component
public class EpidemicValidator extends AbstractValidationHandler<OrderRequest> {
    @Override
    protected void doValidate(OrderRequest request) {
        if (isHighRiskArea(request.getDepartureStation())) {
            throw new ValidationException("HIGH_RISK_AREA", "高风险地区暂不支持购票");
        }
    }
    
    private boolean isHighRiskArea(String station) {
        // 调用疫情API检查
        return false;
    }
}

配置更新:

@Bean
@Qualifier("orderValidatorChain")
public ValidationHandler<OrderRequest> orderValidatorChain(
        @Qualifier("basicValidator") BasicValidator basic,
        @Qualifier("orderValidator") OrderValidator order,
        @Qualifier("epidemicValidator") EpidemicValidator epidemic) {
    basic.setNext(order).setNext(epidemic);
    return basic;
}

代码粗糙,有错误请指明,感谢!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值