变量是表达式树的不可变叶子节点,通过运算符节点(binaryopnode、unaryopnode、callnode等)组合成递归嵌套结构,所有节点统一继承expressionnode并支持访问者模式;求值与替换由外部上下文和replace方法解耦实现。

变量的组合模式不是直接“组合变量”,而是把变量作为表达式树中的叶子节点,再通过运算符节点将它们组装成可递归嵌套的结构。核心在于:用统一接口抽象“能参与运算的东西”——它既可以是原始变量(Leaf),也可以是含子表达式的复合节点(Composite)。
明确变量在表达式树中的角色
变量本身不执行运算,它是表达式树的终端节点(Leaf)。例如 x、y、count 在树中对应 ParameterExpression 或自定义的 VariableNode 类型。关键点:
- 每个变量需有唯一标识(如名称或 ID),便于后续绑定值或替换
- 变量节点不实现
evaluate(),但提供toExpression()方法,返回标准Expression实例(C#)或等效数据结构(JS/其他语言) - 避免让变量持有运行时值——值绑定应由外部上下文(如作用域字典)统一管理,保持节点不可变
设计支持嵌套的运算节点类型
运算符(如加、乘、函数调用)是组合节点(Composite),它们持有一个或多个子节点(可以是变量、常量,也可以是另一个运算节点)。示例结构:
- BinaryOpNode:含 left、right 两个子节点,operator 字段(如 “+”、“*”)
- UnaryOpNode:含 single 子节点,operator 字段(如 “-”、“!”)
- CallNode:含 target(函数名或引用)、args(参数列表,每个都是表达式节点)
所有节点继承自统一基类(如 ExpressionNode),强制实现 accept(visitor) 或 compile(),确保客户端能一致遍历、翻译或执行整棵树。
用组合模式构建嵌套表达式树的典型流程
以 C# 为例,构造 (x + y) * count 的树:
- 创建三个变量节点:
var x = new VariableNode("x");、y、count - 构建内层加法:
var sum = new BinaryOpNode("+", x, y); - 构建外层乘法:
var result = new BinaryOpNode("*", sum, count); - 最终
result就是一个完整、可嵌套、可递归求值的表达式树根节点
这个过程天然支持任意深度嵌套——比如把 count 替换为 new CallNode("getMax", new[] { a, b }),树结构自动扩展,无需修改上层逻辑。
配合作用域实现变量求值与动态替换
表达式树建好后,真正执行需要变量上下文。推荐采用“分离编译与求值”的方式:
- 定义
IEvaluationContext接口,提供GetValue(string name)方法 - 每个节点实现
Evaluate(IEvaluationContext ctx),变量节点查上下文,运算节点递归求值子节点再计算 - 如需动态替换变量(如模板渲染),提供
Replace(string oldName, ExpressionNode newNode)方法,在 Composite 节点中递归查找并更新
这样,同一棵树可在不同上下文中复用(测试用 mock 值、生产用真实数据、调试用采样值)。










