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

基于多谓词的规则引擎设计优化:谓词链改进咨询

优化Rule Engine谓词链式调用的可行方案

针对当前Rule Engine实现中Predicate链式调用冗余、依赖注入不规范的问题,以下是几个落地性强的优化方案:

1. 重构RuleEngine,支持批量规则组合

原RuleEngine仅支持设置单个Predicate且会覆盖原有规则,先重构为支持批量添加规则并自动组合:

public class RuleEngine {
    private final List<Predicate<Transaction>> rules = new ArrayList<>();
    private Transaction transaction;

    public void setTransaction(Transaction transaction) {
        this.transaction = transaction;
    }

    // 添加单个规则
    public void addRule(Predicate<Transaction> rule) {
        this.rules.add(rule);
    }

    // 批量添加规则
    public void addRules(Collection<Predicate<Transaction>> rules) {
        this.rules.addAll(rules);
    }

    public boolean executeRules() {
        // 自动组合所有规则为逻辑与,空规则集默认返回true
        Predicate<Transaction> combinedRule = rules.stream()
                .reduce(Predicate::and)
                .orElse(t -> true);
        boolean isValid = combinedRule.test(transaction);
        if (isValid) {
            // 交易验证通过逻辑
        }
        return isValid;
    }
}

2. 用规则组封装交易类型对应的规则集合

将不同交易类型的规则列表封装到配置类中,替代硬编码的链式调用,提升可读性和可维护性:

@Component
public class PaymentRuleConfig {
    private final PredicateHelper predicateHelper;

    // 构造注入替代@Autowired,符合Spring规范
    public PaymentRuleConfig(PredicateHelper predicateHelper) {
        this.predicateHelper = predicateHelper;
    }

    public List<Predicate<Transaction>> getCardPaymentRules() {
        return List.of(
                predicateHelper.rule1,
                predicateHelper.rule2,
                predicateHelper.rule3
        );
    }

    public List<Predicate<Transaction>> getCashPaymentRules() {
        return List.of(
                predicateHelper.rule1,
                predicateHelper.rule4,
                predicateHelper.rule5
        );
    }
}

修改Payments类,直接传入规则列表:

@Component
public class Payments {
    private final PaymentRuleConfig ruleConfig;

    public Payments(PaymentRuleConfig ruleConfig) {
        this.ruleConfig = ruleConfig;
    }

    public void process(Transaction transaction, String type) {
        RuleEngine ruleEngine = new RuleEngine();
        ruleEngine.setTransaction(transaction);

        switch (type) {
            case "card":
                ruleEngine.addRules(ruleConfig.getCardPaymentRules());
                break;
            case "cash":
                ruleEngine.addRules(ruleConfig.getCashPaymentRules());
                break;
            default:
                // 日志记录逻辑
        }
        ruleEngine.executeRules();
    }
}

3. 用枚举消除Switch-Case,实现类型与规则的映射

进一步用枚举管理交易类型与规则组的对应关系,彻底消除冗余的switch-case:

public enum PaymentType {
    CARD("card", List.of(predicateHelper.rule1, predicateHelper.rule2, predicateHelper.rule3)),
    CASH("cash", List.of(predicateHelper.rule1, predicateHelper.rule4, predicateHelper.rule5));

    private final String code;
    private final List<Predicate<Transaction>> rules;

    PaymentType(String code, List<Predicate<Transaction>> rules) {
        this.code = code;
        this.rules = rules;
    }

    public static Optional<PaymentType> fromCode(String code) {
        return Arrays.stream(values())
                .filter(t -> t.code.equals(code))
                .findFirst();
    }

    public List<Predicate<Transaction>> getRules() {
        return rules;
    }
}

修改Payments类:

@Component
public class Payments {
    public void process(Transaction transaction, String type) {
        RuleEngine ruleEngine = new RuleEngine();
        ruleEngine.setTransaction(transaction);

        PaymentType.fromCode(type)
                .map(PaymentType::getRules)
                .ifPresent(ruleEngine::addRules);

        ruleEngine.executeRules();
    }
}

4. 将规则封装为独立Bean,实现动态组合(进阶方案)

如果规则数量多、需要动态调整,可将每个规则封装为独立Spring Bean,通过自定义注解标记所属交易类型,实现按需加载:

首先定义自定义注解:

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface PaymentRule {
    String[] value(); // 对应的交易类型,比如{"card", "cash"}
}

封装每个规则为独立Bean:

@Component
@PaymentRule({"card", "cash"})
public class Rule1 implements Predicate<Transaction> {
    private final TransactionUtils transactionUtils;

    public Rule1(TransactionUtils transactionUtils) {
        this.transactionUtils = transactionUtils;
    }

    @Override
    public boolean test(Transaction transaction) {
        return "rule1".equals(transactionUtils.getName(transaction));
    }
}

@Component
@PaymentRule("card")
public class Rule2 implements Predicate<Transaction> {
    private final TransactionUtils transactionUtils;

    public Rule2(TransactionUtils transactionUtils) {
        this.transactionUtils = transactionUtils;
    }

    @Override
    public boolean test(Transaction transaction) {
        return "rule2".equals(transactionUtils.getName(transaction));
    }
}
// Rule3-Rule5同理实现

在RuleConfig中通过Spring上下文获取对应类型的规则:

@Component
public class PaymentRuleConfig implements ApplicationContextAware {
    private ApplicationContext context;

    @Override
    public void setApplicationContext(ApplicationContext context) throws BeansException {
        this.context = context;
    }

    public List<Predicate<Transaction>> getRulesByType(String type) {
        return context.getBeansWithAnnotation(PaymentRule.class).values().stream()
                .filter(bean -> {
                    PaymentRule annotation = bean.getClass().getAnnotation(PaymentRule.class);
                    return Arrays.asList(annotation.value()).contains(type);
                })
                .map(Predicate.class::cast)
                .collect(Collectors.toList());
    }
}

最后Payments类直接调用:

@Component
public class Payments {
    private final PaymentRuleConfig ruleConfig;

    public Payments(PaymentRuleConfig ruleConfig) {
        this.ruleConfig = ruleConfig;
    }

    public void process(Transaction transaction, String type) {
        RuleEngine ruleEngine = new RuleEngine();
        ruleEngine.setTransaction(transaction);
        ruleEngine.addRules(ruleConfig.getRulesByType(type));
        ruleEngine.executeRules();
    }
}

5. 用Builder模式简化Predicate链式组合(可选)

如果仍需要保留链式调用写法,可封装Builder类简化:

public class RulePredicateBuilder {
    private Predicate<Transaction> current;

    public static RulePredicateBuilder start() {
        return new RulePredicateBuilder();
    }

    public RulePredicateBuilder and(Predicate<Transaction> rule) {
        current = current == null ? rule : current.and(rule);
        return this;
    }

    public Predicate<Transaction> build() {
        return current == null ? t -> true : current;
    }
}

使用方式:

private Predicate<Transaction> getCardRules(PredicateHelper helper) {
    return RulePredicateBuilder.start()
            .and(helper.rule1)
            .and(helper.rule2)
            .and(helper.rule3)
            .build();
}

内容的提问来源于stack exchange,提问作者Dan

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.15 22:15:14