共计 1950 个字符,预计需要花费 5 分钟才能阅读完成。
概念澄清:当策略模式遇上控制反转
刚开始接触规则引擎时,我也曾被 Skill 和 Rule 这两个概念搞得一头雾水。直到某天调试优惠券叠加 bug 时突然想通:Rule 就像策略模式里的具体算法,而Skill 更像是 Spring 框架里的 Bean 容器。举个例子:

-
Rule 的原子性 :就像策略接口的
execute()方法,必须完整执行且不依赖外部状态。比如风控规则:rule "未成年禁止购买酒精" when $order : Order(customer.age < 18, containsAlcohol()) then reject("AGE_LIMIT_FAIL"); end -
Skill 的上下文感知 :类似
@Service注解的类,可以持有运行时状态。比如优惠券引擎:@Skill(priority = VIP_USER) public class CouponSkill { private List<Coupon> activeCoupons; // 维持优惠券状态 @Action void apply() {// 能访问用户历史订单等上下文} }
实现对比:看 Drools 和 EasyRules 如何分道扬镳
在 Drools 的 Rete 算法实现中,Rule 会被编译成如下伪代码结构:
// Rule 编译结果
AlphaNode1 -> BetaNode2 -> TerminalNode
而 EasyRules 对 Skill 的处理更简单粗暴:
// EasyRules 的 Skill 执行流程
for (Skill skill : skills) {if (skill.evaluate(ctx)) { // 上下文评估
skill.execute(ctx); // 带状态执行
break; // 通常首个匹配即终止
}
}
关键差异在于:Rule 的节点会参与 Rete 网络共享,而Skill 通常独立评估。这导致在 Drools 中混用两者时可能出现诡异的性能问题。
场景适配:电商案例的 AB 面
优惠券叠加(Skill 模式)
@Skill(name="coupon", priority=3)
public class DiscountSkill {
@Condition
public boolean isApplicable(@Fact User user) {return user.getLevel() > VIP_LEVEL;
}
@Action
public void apply(@Fact Order order) {order.applyCoupon("VIP2024"); // 修改订单状态
}
}
反欺诈规则链(Rule 模式)
rule "同 IP 高频下单"
salience 10
when
$stats : IpStats(frequency > 50)
$order : Order(ip == $stats.ip)
then
insert(new FraudMark("IP_RISK"));
end
rule "午夜异常交易"
salience 20
when
$order : Order(hour > 23 || hour < 5)
then
insert(new FraudMark("NIGHT_RISK"));
end
性能陷阱:Rete 网络的隐藏成本
我曾犯过一个典型错误:把本应是 Skill 的会员等级判断写成 Rule,导致每笔订单都要重复计算相同的用户等级。优化方案是:
// 错误写法 - 每个订单独立评估
rule "GoldUserRule" when
$user : User(level == "GOLD")
$order : Order(user == $user)
// 正确写法 - 共享 AlphaNode
rule "CacheUserLevel" when
$user : User()
then
insert(new UserLevelCache($user));
end
rule "GoldUserOptimized" when
$cache : UserLevelCache(level == "GOLD")
$order : Order(user == $cache.user)
生产实践的三个锦囊
- 决策表分离术:
- 业务规则用 Excel 决策表管理
-
技术规则 (如超时控制) 硬编码实现
-
Skill 拆分时机:
- 当需要独立单元测试时
- 当执行耗时超过 500ms 时
-
当需要复用相同条件判断时
-
监控指标设计:
# Rule 执行指标 rule_engine_rule_exec_time{name="fraud_check"} 0.23 # Skill 状态指标 rule_engine_skill_state{name="coupon", attribute="active_coupons"} 5
开放式思考题
在 Serverless 的冷启动环境下,Skill 如果维持状态可能导致严重的性能抖动。但若完全无状态,又可能失去上下文感知的优势。或许可以参考 Lambda 的 Execution Context 设计,采用分层的状态管理策略?这个平衡点值得深入探讨。
正文完
