规则引擎提供了一种新的计算模型。和一般的命令模型(带条件和循环的顺序执行指令)不同,它提供了一组产生式规则。每个规则有一个条件和一个操作,简单地说,你可以认为是一堆的if-then语句。

规则引擎的精妙之处在于,规则可以按照任何顺序编写,而规则引擎可以根据具体场景决定什么时间按照什么顺序来进行执行。

换一个思路理解就是:规则引擎对所有规则进行执行、判断,筛选出符合条件的规则,然后对其进行相应的评估(执行)。这样做的好处时,很多场景都天然的适应这种模式:

if car.owner.hasCellPhone then premium += 100;

if car.model.theftRating > 4 then premium += 200;

if car.owner.livesInDodgyArea && car.model.theftRating > 2 
     then premium += 300;

规则引擎是一种工具,可以更轻松地使用此计算模型进行编程。它可以是一个完整的开发环境,也可以与其他传统的平台一起使用。我这些年看到的大多数都是运用在现有的平台上的工具。同时,也有用这样的工具来构建整个系统的想法,不过聪明人更倾向于把规则引擎仅仅作为系统一部分。生产规则计算模型最适用的还是计算问题的一个子集,所以规则引擎最好是嵌入到大系统中。

你自己也可以构建一个规则引擎,你所需要做的就是创建一堆具有条件和动作的对象,将它们存储在一个集合中,然后遍历它们以评估条件并执行这些动作。但是大多数情况下,当提到“规则引擎”时,是指专门用来构建和运行规则引擎的产品。

使用规则的技术有所不同,比如基于Java对象的API、基于表达式的DSL或基于可录入的GUI。使用高效的算法(例如Rete算法)有助于执行引擎快速评估数百条规则上的条件。

规则引擎的一个重要特性是“chaining(链接)”,当一个规则的执行部分改变了其他规则的判断条件值,从而能够改变整个系统的状态。chaining特性很具有吸引性,因为通过它可以支持更复杂的行为操作,但也会导致规则的难以理解和debug调试。

我遇到过一些使用规则引擎的案例,每次似乎都不是顺顺利利的(也许我不是一个好的样本)。规则引擎核心通常是允许业务人员在不需要程序员配合的情况下自己指定规则。但往往是理想很美好,现实往往很骨感。

虽然如此,在BusinessReadableDSL方面还是有价值的,其实这也是这种计算模型中我觉得有价值的地方。但是这里存在着很多风险。最大的风险便是,当关注一系列规则时,会发现每个规则都能看懂,都有意义,但规则之间的相互影响却是十分复杂的,特别是规则直接的状态关联。

因此经常有人说,建立一个规则系统很容易,但维护它却变得非常困难,因为没人能够理解这种隐式的程序流。这是抛弃命令计算模型带来的问题。而对于命令式代码的所有错误,理解起来是相对容易的。在使用规则引擎时,某些看起来很容易就能实现的功能点改造,往往会导致一系列意想不到的结果。

关于规则引擎的处理,个人觉得应该遵循以下一些准则:

  • 限制规则的数量,当规则的数量比较多时,往往会带来性能和对规则理解的问题;
  • 对于规则之间的关联要非常小心,尽量通过组织的方式限制甚至避免规则之间的关联;
  • 测试在很多场景下是被低估的,但针对这种隐式行为,测试就显得十分重要了。
  • 在构建规则系统时,建议通过修改规则库来做会早期会引起令人疼痛的事。

基于以上这些原因,尽量避免使用规则引擎。规则引擎的基本思想很简单,但为了更好的控制那些隐式行为,需要在设计规则时尽量限制规则的数量。同时,在构建规则时将规则限制在比较窄的业务范围内。

英文原文:https://martinfowler.com/bliki/RulesEngine.html



你的系统是否适合使用规则引擎?插图

关注公众号:程序新视界,一个让你软实力、硬技术同步提升的平台

除非注明,否则均为程序新视界原创文章,转载必须以链接形式标明本文链接

本文链接:https://choupangxia.com/2021/03/27/use-rule-engine/