这是我参与「第五届青训营 」伴学笔记创作活动的第 8 天
规则引擎
规则引擎可以理解为一个将数据和规则作为输入的系统,它能够将这些规则应用于数据,并根据规则为我们提供输出。规则引擎的引入能够大大提高系统的灵活性和扩展性,本文将对规则引擎的产生背景以及设计原理做系统介绍。
产生背景
首先是为什么需要规则引擎,如果从开发人员的视角来看,在规则引擎出现之前,想要处理有些逻辑比较复杂的业务,只有不断地增添执行条件(例如 if-else)去满足我们这个复杂的业务场景,而且一旦业务逻辑发生变化就需要修改代码重新上线,这显然是十分低效的。
从业务人员的视角来看也存在诸多弊端,以前的开发模式是业务人员提出业务规则叫开发人员做出相对应的业务开发,到底这个最后开发出来的业务规则是否和业务人员所提出的一致,需要通过大量的测试去进行验证。因此迫切需要分离业务人员的商业决策逻辑和开发人员的技术决策逻辑,规则引擎就是应用于这种动态环境中的一种解决方法。两者的区别如下图所示:
有了规则引擎之后,我们就可以有下面几点提升:
- 业务人员独立配置业务规则,开发人员无需理解,让业务人员的规则和真正的实际情况一致。
- 增加业务的透明程度,业务人员配置了之后其他业务人员也能够知道,以前只能通过代码扣扣相传。
- 规则高效改动和上线,一般业务人员提出需求之后都是希望能尽快上线,但是之前都需要有代码开发,项目上线等环节,现在业务人员配置好了之后即配即用。
定义
💡 规则引擎由推理引擎发展而来,是一种嵌入在应用程序中的组件,实现了将业务决策从应用程序代码中分离出来,并使用预定义的语言模块编写业务决策。接受数据输入,解释业务规则,并根据规则做出业务决策。业务规则
一个业务规则包含一组条件和在此条件下执行的操作,它们表示业务规则应用程序的一段业务逻辑。业务规则通常应该由业务分析人员和策略管理者开发和修改,但有些复杂的业务规则也可以由技术人员使用面向对象的技术语言或脚本来定制。业务规则的理论基础是:设置一个或多个条件,当满足这些条件时会触发一个或多个操作。
规则引擎的功能
由于规则引擎是软件组件,所以只有开发人员才能够通过程序接口的方式来使用和控制它,规则引擎的程序接口至少包含以下几种API:
- 加载和卸载规则集的API;
- 数据操作的API;
- 引擎执行的API。
开发人员在程序中使用规则引擎基本遵循以下5个典型的步骤:
- 创建规则引擎对象;
- 向引擎中加载规则集或更换规则集;
- 向引擎提交需要被规则集处理的数据对象集合;
- 命令引擎执行;
- 导出引擎执行结果,从引擎中撤出处理过的数据。
使用了规则引擎之后,许多涉及业务逻辑的程序代码基本被这五个典型步骤所取代。一个开放的业务规则引擎应该可以”嵌入”在应用程序的任何位置,不同位置的规则引擎可以使用不同的规则集,用于处理不同的数据对象。此外,对使用引擎的数量没有限制。
实现
一个规则引擎的实现可以参考编译原理相关知识,因为它的目的本质上是将业务逻辑表达式编译成底层代码,整个过程可以划分为词法分析、语法分析和语义分析三个部分,其中语义分析涉及的问题过于复杂,因为机器不想人一样,能够在特定的上下文语境下理解语句表达的意义,因此一般只考虑词法分析和语法分析两个过程。
词法分析
词法分析就是把源代码字符串转换为词法单元(Token)的这个过程,所谓 Token,就是源文件中不可再进一步分割的一串字符,类似于英语中的单词。英语中的单词的数量是有限的,程序语言中可用的 token 的类别也是有限的,而且是非常少的。一般来说程序语言中的 token 有:
- 常数:整数、小数、字符、字符串等;
- 操作符:算术操作符、比较操作符、逻辑操作符;
- 分割符:逗号、分号、括号等;
- 保留字,标识符:变量名、函数名、类名等;
词法分析的方法一般有直接扫描和正则表达式匹配扫描两种,直接扫描的思路非常简单,每轮扫描根据第一个字符判断属于哪种类型的 token,然后采取不同的策略扫描出一个完整的 token,再接着进行下一轮扫描,这种方法的缺点是扫描速度非常慢,需要不断查找和比较字符串,而且不容易扩展,只适用于语法简单的语言。正则表达式匹配扫描的原理就是有限状态自动机(finate automaton),是用来判断字符串(句子)是否和正则表达式匹配的状态机,它有一个字母表 Σ 、一个状态集合 S ,一个转换函数 T ,当它处于某个状态时,若它读入了一个字符(必须是字母表里的字符),则会根据当前状态和读入的字符自动转换到另一个状态,它有一个初始状态,还有一些所谓的接受状态。
它的工作过程是:首先自动机处于初始状态,之后它开始读入字符串,每读入一个字符,它都根据当前状态和读入字符转换到下一状态,直到字符串结束,若此时自动机处于其接受状态,则表示该字符串被此自动机接受。如下图所示:
数学家们已经证明了:任何一个正则表达式都有一个等价的有限状态自动机,任何一个有限状态自动机也有一个等价的正则表达式。可以看出有限状态自动机的判断速度是非常快的,它只要求对字符串扫描一遍就可以了,显然比前面介绍的直接扫描法要快得多。
语法分析
如果把词法分析看作为字母组合成单词的过程,那么语法分析就是一个把单词组合成句子的过程。正如在词法分析中使用正则表达式来描述词法的规则一样,我们在语法分析中使用一种比 RE 表达能力更强的工具 —— 上下文无关文法,来描述语言的语法规则。我们可以把某一种语言看成无数个符合语法规则的句子的集合,根据给定的上下文无关语法我们可以判断某一个 Token 串是否符合某个语法规则;如果符合,那么我们可以把此文法和对应输入的 Token 串组合起来生成一个句子。整个流程如下图所示:
上下文无关语法(context-free grammar, CFG),是一种用来对某种语言进行形式化的、精确的描述的工具。有了这个工具,我们就可以很方便的定义一种语言的语法了。一种 CFG 由四个部分组成,分别是:
- N:非终结符的集合;
- T:终结符的集合;
- P:产生式规则集合;
- S:(唯一的)起始符号;
巴科斯范式(Backus Normal Form,BNF)是描述上下文无关理论的一种具体方法,通过BNF可以实现上下文无关文法的具体化、公式化、科学化,是实现代码解析的必要条件。
💡 BNF本质上就是树形分解,分解成一棵抽象语法树- 每个产生式就是一个子树,在写编译器时,每个子树对应一个解析函数。
- 叶子节点叫做 终结符,非叶子节点叫做 非终结符。
实现语法分析过程中常用的算法有自顶向下分析算法、递归下降分析算法、LL(1)分析算法、自底向上分析算法这几种,感兴趣的话可以自行查阅学习,在这里就不再赘述。