You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Java Combinator Pattern注册校验中apply方法是否重复调用问题

参考代码

public interface CustomerRegVali extends Function<Customer, ValidationResult> {

    static CustomerRegVali isEmailValid(){
        return customer -> customer.getEmail().contains("@") ?
                SUCCESS : EMAIL_NOT_VALID;
    }

    static CustomerRegVali isDobValid(){
        return customer -> Period.between(customer.getDob(), LocalDate.now()).getYears() > 16 ?
                SUCCESS : NOT_ADULT;
    }
    
    static CustomerRegVali isPhoneValid(){
        return customer -> customer.getPhone().startsWith("+0") ?
                SUCCESS : PHONE_NOT_VALID;
    }

    default CustomerRegVali and(CustomerRegVali other){
        return customer -> {
            ValidationResult result = CustomerRegVali.this.apply(customer);
            return result.equals(SUCCESS) ? other.apply(customer) : result;
        };
    }
}

// 主方法调用逻辑
ValidationResult result = isEmailValid()
        .and(isPhoneValid())
        .and(isDobValid())
        .apply(customer);

结论

不存在冗余调用,每个基础校验的apply方法最多只会执行1次

执行逻辑说明

你实现的and组合方法是标准的短路逻辑,整个调用流程分为两个阶段:

  • 规则组装阶段:isEmailValid().and(isPhoneValid()).and(isDobValid())这段链式调用仅完成校验规则的包装拼接,不会触发任何校验逻辑,也不会调用任何apply方法。
  • 实际校验阶段:只有最后调用apply(customer)时才会逐层执行校验:
    • 先执行isEmailValid的校验逻辑,失败直接返回对应错误,后续校验完全不会触发
    • 邮箱校验通过才会执行isPhoneValid的校验逻辑,失败直接返回,不会触发年龄校验
    • 手机号校验通过才会执行isDobValid的校验逻辑

实现优势

这个组合器模式的实现是非常规范的:

  • 校验规则和组合逻辑完全解耦,新增校验规则仅需新增对应静态方法即可
  • 短路逻辑可以避免不必要的计算,性能表现优秀
  • 链式调用的写法可读性极强,校验顺序一目了然

内容的提问来源于stack exchange,提问作者Rasmus Hjorth Lüdeking

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.04 17:45:03