1. 规则执行器的设计背景与核心思路最近在开发一个用户试用申请系统的规则扩展功能时遇到了一个典型的条件判断难题。原有的系统通过大量if-else语句来实现各种条件判断随着业务规则越来越复杂代码变得难以维护。比如要判断用户是否符合试用条件需要检查用户所在地区是否在服务范围内用户账号是否完成实名认证用户历史订单是否超过限制用户信用评分是否达标这些条件之间有的是与关系所有条件都要满足有的是或关系满足任一即可。更麻烦的是有些条件的判断成本很高比如调用外部信用评分接口如果前面的条件已经不满足后续的判断其实没必要执行。1.1 传统if-else方案的痛点在原有系统中代码大概是这样的结构if(regionService.check(user.getRegion())) { if(user.isVerified()) { if(orderService.checkOrderCount(user.getId()) || creditService.checkScore(user.getId())) { // 通过申请 } } }这种写法有几个明显问题嵌套层级太深可读性差新增或修改规则需要改动核心逻辑无法实现短路求值比如region检查不通过时仍然会执行后续检查单元测试困难各种条件组合需要大量测试用例1.2 规则执行器的设计思路规则执行器的核心思想是将业务规则抽象为独立的对象通过执行器来统一管理和执行这些规则。具体来说每个业务规则实现统一的接口执行器负责按顺序执行规则支持AND/OR等逻辑关系支持短路求值某个规则失败后跳过后续不必要检查规则之间通过上下文共享数据这样设计后业务规则的变更就只需要新增或修改规则类不会影响核心执行逻辑。2. 规则执行器的具体实现2.1 规则接口设计首先定义一个基础的规则接口public interface RuleT { /** * 执行规则检查 * param context 执行上下文 * return 检查结果 */ boolean evaluate(T context); /** * 规则名称用于日志和监控 */ String getName(); /** * 是否应该继续执行后续规则用于短路逻辑 */ default boolean shouldContinueOnFailure() { return false; } }2.2 具体规则实现然后针对每个业务条件实现具体的规则类。例如地区检查规则public class RegionRule implements RuleApplyContext { Override public boolean evaluate(ApplyContext context) { return regionService.check(context.getUser().getRegion()); } Override public String getName() { return RegionRule; } }信用评分规则public class CreditScoreRule implements RuleApplyContext { Override public boolean evaluate(ApplyContext context) { // 如果已经检查过信用评分直接使用缓存结果 if(context.getCreditScore() ! null) { return context.getCreditScore() 600; } // 否则调用信用服务获取评分 int score creditService.getScore(context.getUser().getId()); context.setCreditScore(score); // 缓存结果供其他规则使用 return score 600; } Override public String getName() { return CreditScoreRule; } }2.3 执行器实现执行器负责管理规则并控制执行流程public class RuleEngineT { private final ListRuleT rules new ArrayList(); public void addRule(RuleT rule) { rules.add(rule); } public boolean execute(T context) { for (RuleT rule : rules) { boolean result rule.evaluate(context); if (!result !rule.shouldContinueOnFailure()) { return false; // 短路返回 } } return true; } }对于OR关系的规则组可以这样实现public class OrRuleGroupT implements RuleT { private final ListRuleT rules new ArrayList(); public void addRule(RuleT rule) { rules.add(rule); } Override public boolean evaluate(T context) { for (RuleT rule : rules) { if (rule.evaluate(context)) { return true; // 任一规则通过即可 } } return false; } }2.4 上下文设计上下文对象用于在规则间共享数据public class ApplyContext { private User user; private Integer creditScore; private Integer orderCount; // 其他共享字段... // getters and setters }3. 规则执行器的使用示例3.1 构建规则引擎RuleEngineApplyContext engine new RuleEngine(); // AND关系的规则 engine.addRule(new RegionRule()); engine.addRule(new VerificationRule()); // OR关系的规则组 OrRuleGroupApplyContext orGroup new OrRuleGroup(); orGroup.addRule(new OrderCountRule()); orGroup.addRule(new CreditScoreRule()); engine.addRule(orGroup);3.2 执行规则检查ApplyContext context new ApplyContext(); context.setUser(currentUser); boolean passed engine.execute(context); if (passed) { // 通过申请 } else { // 拒绝申请 }4. 规则执行器的进阶优化4.1 性能优化技巧规则排序把失败概率高的简单规则放在前面可以尽早短路结果缓存对于耗时的规则检查如信用评分结果可以缓存在上下文中并行执行对于没有依赖关系的规则可以并行执行// 并行执行示例 public boolean parallelExecute(T context) { return rules.parallelStream() .allMatch(rule - rule.evaluate(context) || rule.shouldContinueOnFailure()); }4.2 监控与调试记录每个规则的执行结果和耗时提供规则执行轨迹方便排查问题支持动态调整规则顺序或开关public boolean executeWithMonitor(T context) { for (RuleT rule : rules) { long start System.currentTimeMillis(); boolean result rule.evaluate(context); long cost System.currentTimeMillis() - start; monitor.record(rule.getName(), result, cost); if (!result !rule.shouldContinueOnFailure()) { return false; } } return true; }4.3 规则配置化可以将规则配置存储在数据库或配置文件中实现动态加载{ rules: [ { name: RegionRule, className: com.example.rules.RegionRule, continueOnFailure: false }, { name: CreditOrOrderRule, type: OR, rules: [ { className: com.example.rules.OrderCountRule }, { className: com.example.rules.CreditScoreRule } ] } ] }5. 规则执行器的适用场景与局限性5.1 适用场景复杂的业务规则判断需要频繁变更的业务逻辑多条件组合的判断场景需要详细执行记录的业务流程5.2 局限性对于简单的条件判断可能会过度设计规则之间的数据依赖需要小心处理调试复杂度比直接写if-else高5.3 替代方案比较策略模式适合行为可替换的场景责任链模式适合流程处理的场景状态机适合有明确状态转移的场景DSL规则引擎如Drools适合非常复杂的业务规则在实际项目中我通常会先使用简单的规则执行器模式当规则复杂度达到一定程度后再考虑引入完整的规则引擎。过早优化和过度设计都会带来维护成本。6. 实际项目中的经验教训上下文设计要谨慎避免在上下文中存放过多数据导致规则间隐式耦合规则粒度要适中太细的规则会导致数量爆炸太粗的规则失去灵活性注意线程安全如果规则引擎被多线程共享需要确保规则实现是线程安全的版本兼容性当规则接口变更时要考虑已有规则的兼容处理一个常见的错误是在规则中直接修改上下文中的共享对象这会导致难以追踪的副作用。更好的做法是让规则返回需要更新的数据由执行器统一应用变更。// 不推荐的做法 public class BadRule implements RuleApplyContext { public boolean evaluate(ApplyContext context) { context.setSomeField(computeValue()); // 直接修改上下文 return true; } } // 推荐的做法 public class GoodRule implements RuleApplyContext { public boolean evaluate(ApplyContext context) { return computeValue(); // 返回计算结果 } } // 在执行器中处理结果 if (rule.evaluate(context)) { context.setSomeField(((GoodRule)rule).getComputedValue()); }规则执行器模式特别适合业务规则复杂的系统如风控系统、促销系统、工作流系统等。通过将业务规则从主流程中解耦出来可以大大提高系统的可维护性和扩展性。