设计一个轻量级规则引擎,核心是实现数据结构定义、条件解析器和动作执行器。通过将业务逻辑与代码解耦,实现规则的动态配置与高效执行。

为什么需要规则引擎

在日常业务开发中,硬编码(Hardcoding)往往面临以下痛点:

规则引擎的核心价值:彻底解耦业务规则与系统代码。将“如果满足条件 A,就执行动作 B”的决策逻辑从业务代码中抽离,交由引擎统一管理,实现规则的在线配置、动态更新与实时生效

核心概念与异同对比

概念区分

硬编码 vs 规则引擎

对比维度硬编码实现规则引擎实现
规则与代码耦合度极高,规则写死在代码中极低,规则与代码完全解耦
规则迭代效率极低(需编译打包上线)极高(在线配置,分钟级生效)
规则可维护性极差,散落多处,难排查极好,集中管理、版本控制
上线风险高(需全量回归)低(支持灰度发布与动态热更新)

规则引擎相关的设计模式

这是关于规则引擎最常被问到的问题之一。直观上,规则引擎允许你在运行时替换不同的"规则策略",看起来很像策略模式(Strategy Pattern),但实际并非如此。

策略模式 vs 规则引擎

对比维度策略模式规则引擎
解决的问题算法替换(同接口、不同实现)复杂业务规则的编排与执行
规则数量通常 ≤ 10 个可以成百上千条
规则来源编码时确定,编译时绑定运行时动态加载(DB、配置文件、DSL)
条件复杂度简单选择逻辑(如 switch)支持组合条件、优先级、冲突解决
核心机制多态 + 接口注入推理引擎(如 Rete 算法)或 AST 求值

策略模式的核心:你有一组实现同一接口的类,在编码时就能确定它们的接口和数量,通过简单的选择逻辑(如参数 switch)来替换。这是一个算法替换模式。

规则引擎的核心:规则的数量、内容、编排方式都是运行时才确定的,开发者无法在编译期预见所有规则。引擎需要自己负责条件匹配、优先级排序、冲突解决——这些是策略模式无法覆盖的。

规则引擎是多个设计模式的复合体

规则引擎更像以下模式的组合:

一句话总结

如果你只是把 if-else 提取成多个可替换的策略类,并在编码时选择其中一个,那是策略模式。但一个完整的规则引擎远远超出了策略模式的范畴——它是解释器模式 + 责任链模式 + 组合模式的复合体,再加上自己的推理机制(Rete 算法、AST 求值等)。规则引擎不是策略模式的应用,而是对策略模式的超越和升华

规则引擎数据结构模型

规则引擎的核心数据结构遵循 Rule → Condition → Action 的三层模型,直观理解如下:

D2 Diagram
qtopie.github.io

从图中可以清晰地看到:

规则引擎架构与核心算法

一个完备的规则引擎架构通常包含以下 5 大核心模块:

D2 Diagram
qtopie.github.io

从架构图可以清晰地看到上下两条链路:

底层算法补充: Drools 等企业级引擎多采用 Rete / Phreak 算法,其核心思想是“以空间换时间”,将规则构建为有向无环图,共享公共的条件节点(Alpha/Beta 节点),避免海量规则重复计算条件。

基于 Go 语言设计与实现轻量级规则引擎

下面使用 Go 语言 实现一个基于 抽象语法树 (AST) / 逻辑条件树 的轻量级规则引擎。

核心特性

Go 代码实现

package ruleengine

import (
	"fmt"
	"reflect"
	"strings"
	"sync"
)

// Operator 比较操作符
type Operator string

const (
	OpEq       Operator = "="
	OpNe       Operator = "!="
	OpGt       Operator = ">"
	OpGte      Operator = ">="
	OpLt       Operator = "<"
	OpLte      Operator = "<="
	OpContains Operator = "CONTAINS"
)

// LogicOperator 逻辑操作符
type LogicOperator string

const (
	LogicAnd LogicOperator = "AND"
	LogicOr  LogicOperator = "OR"
)

// Condition 单个条件(原子节点)
type Condition struct {
	Field    string      `json:"field"`    // Fact 中的字段 key
	Operator Operator    `json:"operator"` // 比较操作符
	Value    interface{} `json:"value"`    // 期望目标值
}

// Evaluate 校验单个条件
func (c *Condition) Evaluate(fact map[string]interface{}) bool {
	val, exists := fact[c.Field]
	if !exists {
		return false
	}

	switch c.Operator {
	case OpEq:
		return reflect.DeepEqual(val, c.Value)
	case OpNe:
		return !reflect.DeepEqual(val, c.Value)
	case OpGt:
		return toFloat64(val) > toFloat64(c.Value)
	case OpGte:
		return toFloat64(val) >= toFloat64(c.Value)
	case OpLt:
		return toFloat64(val) < toFloat64(c.Value)
	case OpLte:
		return toFloat64(val) <= toFloat64(c.Value)
	case OpContains:
		str, ok := val.(string)
		substr, ok2 := c.Value.(string)
		return ok && ok2 && strings.Contains(str, substr)
	default:
		return false
	}
}

// RuleNode 表达式节点(可以包含直接条件或子节点逻辑树)
type RuleNode struct {
	Logic      LogicOperator `json:"logic,omitempty"`      // AND / OR
	Conditions []Condition   `json:"conditions,omitempty"` // 单条件列表
	Children   []RuleNode    `json:"children,omitempty"`   // 嵌套子节点
}

// Evaluate 递归求值表达式树
func (n *RuleNode) Evaluate(fact map[string]interface{}) bool {
	// 如果是组合逻辑节点 (AND / OR)
	if n.Logic == LogicOr {
		for _, c := range n.Conditions {
			if c.Evaluate(fact) {
				return true
			}
		}
		for _, child := range n.Children {
			if child.Evaluate(fact) {
				return true
			}
		}
		return false
	}

	// 默认使用 AND 逻辑
	for _, c := range n.Conditions {
		if !c.Evaluate(fact) {
			return false
		}
	}
	for _, child := range n.Children {
		if !child.Evaluate(fact) {
			return false
		}
	}
	return true
}

// Action 规则命中后的触发动作函数
type Action func(fact map[string]interface{}) interface{}

// Rule 规则对象
type Rule struct {
	ID       string   `json:"id"`
	Name     string   `json:"name"`
	Priority int      `json:"priority"` // 优先级,越大越优先
	RootNode RuleNode `json:"root_node"`
	ActionFn Action   `json:"-"`
}

// Engine 规则引擎(包含线程安全的热更新与执行)
type Engine struct {
	mu    sync.RWMutex
	rules map[string]*Rule
}

func NewEngine() *Engine {
	return &Engine{
		rules: make(map[string]*Rule),
	}
}

// RegisterRule 注册/更新规则(支持热加载)
func (e *Engine) RegisterRule(rule *Rule) {
	e.mu.Lock()
	defer e.mu.Unlock()
	e.rules[rule.ID] = rule
}

// RemoveRule 卸载规则
func (e *Engine) RemoveRule(ruleID string) {
	e.mu.Lock()
	defer e.mu.Unlock()
	delete(e.rules, ruleID)
}

// Execute 传入 Fact 数据,触发匹配的规则
func (e *Engine) Execute(fact map[string]interface{}) map[string]interface{} {
	e.mu.RLock()
	defer e.mu.RUnlock()

	results := make(map[string]interface{})

	for _, rule := range e.rules {
		if rule.RootNode.Evaluate(fact) {
			if rule.ActionFn != nil {
				results[rule.ID] = rule.ActionFn(fact)
			} else {
				results[rule.ID] = "MATCHED"
			}
		}
	}
	return results
}

// 辅助数值转换函数
func toFloat64(val interface{}) float64 {
	switch v := val.(type) {
	case int:
		return float64(v)
	case int64:
		return float64(v)
	case float64:
		return v
	case float32:
		return float64(v)
	default:
		return 0
	}
}

模拟电商风控/折扣场景使用示例

package main

import (
	"fmt"
	"ruleengine"
)

func main() {
	// 1. 初始化规则引擎
	engine := ruleengine.NewEngine()

	// 2. 配置规则:VIP大额订单打折规则 ( (Amount >= 1000 AND UserLevel == 3) OR UserTags CONTAINS "VIP" )
	discountRule := &ruleengine.Rule{
		ID:       "rule_discount_001",
		Name:     "大额 VIP 订单打折规则",
		Priority: 10,
		RootNode: ruleengine.RuleNode{
			Logic: ruleengine.LogicOr,
			Children: []ruleengine.RuleNode{
				{
					Logic: ruleengine.LogicAnd,
					Conditions: []ruleengine.Condition{
						{Field: "amount", Operator: ruleengine.OpGte, Value: 1000},
						{Field: "user_level", Operator: ruleengine.OpEq, Value: 3},
					},
				},
			},
			Conditions: []ruleengine.Condition{
				{Field: "user_tag", Operator: ruleengine.OpContains, Value: "VIP"},
			},
		},
		ActionFn: func(fact map[string]interface{}) interface{} {
			amount := fact["amount"].(int)
			discountAmount := float64(amount) * 0.8
			return fmt.Sprintf("匹配成功!原价 %d,享8折优惠,现价: %.2f", amount, discountAmount)
		},
	}

	// 3. 注册规则到引擎
	engine.RegisterRule(discountRule)

	// 4. 输入 Fact 事实对象模拟测试
	fact1 := map[string]interface{}{
		"amount":     1200,
		"user_level": 3,
		"user_tag":   "NORMAL",
	}

	fact2 := map[string]interface{}{
		"amount":     200,
		"user_level": 1,
		"user_tag":   "NORMAL",
	}

	fmt.Println("--- 测试 Fact 1 (满足大额VIP) ---")
	res1 := engine.Execute(fact1)
	for ruleID, res := range res1 {
		fmt.Printf("[%s]: %v\n", ruleID, res)
	}

	fmt.Println("\n--- 测试 Fact 2 (不满足规则) ---")
	res2 := engine.Execute(fact2)
	if len(res2) == 0 {
		fmt.Println("未命中任何规则")
	}
}

生产落地与治理建议