1175 字
约 3 分钟
1
DSL 是什么?如何定义规则并映射成 Java 对象

DSL 是什么?如何定义规则并映射成 Java 对象

在很多规则引擎、工作流、搜索条件、配置系统中,经常会看到 DSL。

DSL 全称:

Domain Specific Language

中文一般叫:

领域特定语言

它本质上就是:

为某一个特定业务领域设计的一套“小语言”。

比如我们设计一个优惠规则 DSL:

age > 18 && vip == true

它表达的业务含义就是:

年龄大于 18,并且是 VIP 用户

相比直接把规则写死在 Java:

if (user.getAge() > 18 && user.isVip()) {
    // ...
}

DSL 最大的价值是:

规则和代码解耦。

以后修改规则时,不一定需要重新修改 Java 代码。


一、DSL 本质是什么?

一个 DSL 通常由三部分组成:

语法
语义
执行逻辑

例如:

age >= 18

这里:

age

是字段。

>=

是操作符。

18

是值。

因此可以把一条 DSL 规则抽象成:

字段 + 操作符 + 值

Java 对象可以定义成:

public class Rule {

    private String field;

    private String operator;

    private Object value;

}

DSL:

age >= 18

解析以后就是:

Rule rule = new Rule();

rule.setField("age");
rule.setOperator(">=");
rule.setValue(18);

这就是最简单的:

DSL -> Java Object

二、DSL 如何定义规则?

稍微复杂一点的 DSL:

age >= 18 && level == "VIP"

它实际上包含两个规则:

age >= 18

和:

level == "VIP"

中间通过:

&&

连接。

因此 DSL 可以抽象成一棵树:

        AND
       /   \
 age >= 18  level == VIP

对应 Java 对象可以设计为:

public interface Expression {
}

普通条件:

public class Condition implements Expression {

    private String field;

    private String operator;

    private Object value;
}

逻辑条件:

public class LogicExpression implements Expression {

    private String logic;

    private Expression left;

    private Expression right;
}

于是:

age >= 18 && level == "VIP"

最终会变成:

LogicExpression
├── logic = AND
├── left
│   ├── field = age
│   ├── operator = >=
│   └── value = 18
└── right
    ├── field = level
    ├── operator = ==
    └── value = VIP

这就是 DSL 最核心的思想:

DSL 最终通常都会被解析成一棵表达式树。

这棵树也经常叫:

AST

全称:

Abstract Syntax Tree

即:

抽象语法树

三、DSL 如何映射成 Java 对象?

整体流程通常是:

DSL 字符串
   ↓
词法解析
   ↓
语法解析
   ↓
AST
   ↓
Java 对象
   ↓
执行

例如 DSL:

age >= 18 && vip == true

第一步拆成 Token:

age
>=
18
&&
vip
==
true

然后识别结构:

Condition
AND
Condition

最后生成 Java 对象:

LogicExpression root = new LogicExpression();

root.setLogic("AND");

root.setLeft(
    new Condition("age", ">=", 18)
);

root.setRight(
    new Condition("vip", "==", true)
);

后面的规则执行器只需要处理 Java 对象:

boolean execute(Expression expression) {

    if (expression instanceof Condition condition) {
        return executeCondition(condition);
    }

    if (expression instanceof LogicExpression logic) {

        boolean left = execute(logic.getLeft());
        boolean right = execute(logic.getRight());

        if ("AND".equals(logic.getLogic())) {
            return left && right;
        }

        if ("OR".equals(logic.getLogic())) {
            return left || right;
        }
    }

    return false;
}

因此真正执行规则的时候,实际上已经不关心 DSL 字符串了。

执行的是:

DSL
↓
AST
↓
Java Object
↓
Rule Executor

四、实际项目里怎么做?

简单 DSL 可以自己解析:

String rule = "age >= 18";

String[] parts = rule.split(" ");

String field = parts[0];
String operator = parts[1];
String value = parts[2];

但是 DSL 一旦支持:

&&
||
()
>
<
>=
<=
==
!=
IN
NOT IN

例如:

(age >= 18 && vip == true)
||
(level == "SVIP" && score > 1000)

就不建议手写字符串解析了。

通常会使用:

ANTLR

来定义 DSL Grammar。

例如:

expr
    : expr AND expr
    | expr OR expr
    | condition
    | '(' expr ')'
    ;

condition
    : IDENTIFIER OPERATOR VALUE
    ;

ANTLR 会根据 Grammar 帮我们生成 Parser。

整体结构就变成:

DSL
 ↓
ANTLR Lexer
 ↓
ANTLR Parser
 ↓
ParseTree / AST
 ↓
Java Object
 ↓
业务执行器

五、总结

DSL 可以简单理解成:

用一套接近业务语言的语法描述业务规则。

例如:

age >= 18 && vip == true

程序内部不会直接执行这段字符串,而是:

DSL
 ↓
解析
 ↓
AST
 ↓
Java Object
 ↓
执行器

所以设计 DSL 时,真正重要的不是字符串怎么写,而是先设计好:

Rule
Condition
Expression
Operator
LogicExpression

这些核心领域对象。

因为:

DSL 只是外部表现形式,AST 和 Java 对象才是程序真正处理的规则模型。

DSL 是什么?如何定义规则并映射成 Java 对象
http://www.clxhxhhr.top/posts/640/
作者
clxstart
发布于
2026-09-16
许可协议
CC BY-NC-SA 4.0
评论
0 条
还没有评论,先写一条吧。