解释器(Interpreter)模式
# 解释器(Interpreter)模式
给分析对象定义一个语言,并定义该语言的文法表示,再设计一个解析器来解释语言中的句子。也就是说,用编译语言的方式来分析应用中的实例。这种模式实现了文法表达式处理的接口,该接口解释一个特定的上下文。类行为型模式
- 抽象表达式(Abstract Expression)角色:定义解释器的接口,约定解释器的解释操作,主要包含解释方法 interpret ()。
- 终结符表达式(Terminal Expression)角色:是抽象表达式的子类,用来实现文法中与终结符相关的操作,文法中的每一个终结符都有一个具体终结表达式与之相对应。
- 非终结符表达式(Nonterminal Expression)角色:也是抽象表达式的子类,用来实现文法中与非终结符相关的操作,文法中的每条规则都对应于一个非终结符表达式。
- 环境(Context)角色:通常包含各个解释器需要的数据或是公共的功能,一般用来传递被所有解释器共享的数据,后面的解释器可以从这里获取这些值。
- 客户端(Client):主要任务是将需要分析的句子或表达式转换成使用解释器对象描述的抽象语法树,然后调用解释器的解释方法,当然也可以通过环境角色间接访问解释器的解释方法。

抽象表达式(Abstract Expression)角色:定义解释器的接口,约定解释器的解释操作,主要包含解释方法 interpret ()。
/**
* 身份信息表达式
* 表达式的解析器
*/
public abstract class IDCardExpression {
abstract boolean interpret(String expression);
}
1
2
3
4
5
6
7
8
2
3
4
5
6
7
8
终结符表达式(Terminal Expression)角色:是抽象表达式的子类,用来实现文法中与终结符相关的操作,文法中的每一个终结符都有一个具体终结表达式与之相对应。
public class TerminalExpression extends IDCardExpression {
Set<String> data; // 免费数据
String symbol; // 定义解析用的符号 如 : -
public TerminalExpression(Set<String> data, String symbol) {
this.data = data;
this.symbol = symbol;
}
@Override
boolean interpret(String expression) {
// 上海市:张文宏-医生 按照指定符号分割
String[] split = expression.split(symbol);
// 冒号: 上海市
// 横杠 上海市:张文宏 医生
for (String s : split) {
// 在免费城市列表中或是免费人群列表中的
if (data.contains(s)) {
return true;
}
}
return false;
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
非终结符表达式(Nonterminal Expression)角色:也是抽象表达式的子类,用来实现文法中与非终结符相关的操作,文法中的每条规则都对应于一个非终结符表达式。
public class OrExpression extends IDCardExpression {
// 组合两个终结表达式,最终的判断结果是终结表达式判断出来的,这个表达式只是一个桥梁
private IDCardExpression cityExp;
private IDCardExpression typeExp;
public OrExpression(IDCardExpression cityExp, IDCardExpression typeExp) {
this.cityExp = cityExp;
this.typeExp = typeExp;
}
@Override
boolean interpret(String expression) {
// 定义所有终结表达式的合并逻辑
return cityExp.interpret(expression) || typeExp.interpret(expression);
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
环境(Context)角色:通常包含各个解释器需要的数据或是公共的功能,一般用来传递被所有解释器共享的数据,后面的解释器可以从这里获取这些值。
public class Area {
Set<String> city = new HashSet<>();// 免费城市
Set<String> type = new HashSet<>(); // 免费人群
IDCardExpression idCardReader; // 读卡器,表达式解析器
public Area() {
city.add("武汉市");
city.add("上海市");
type.add("医生");
type.add("老人");
type.add("儿童");
// 最小解析
TerminalExpression city = new TerminalExpression(this.city, ":");
TerminalExpression type = new TerminalExpression(this.type, "-");
// 以上满足一个即可
idCardReader = new OrExpression(city, type);
}
void getTicket(String expression) {
boolean interpret = idCardReader.interpret(expression);
if (interpret) {
System.out.println("免费票");
} else {
System.out.println("5元门票");
}
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
测试
public class MainTest {
public static void main(String[] args) {
Area area = new Area();
String s = "上海市:张文宏-医生";
area.getTicket(s);
s = "广州市:吴先生-快递员";
area.getTicket(s);
s = "深圳市:张山-医生";
area.getTicket(s);
}
}
1
2
3
4
5
6
7
8
9
10
11
2
3
4
5
6
7
8
9
10
11
# 应用场景
什么场景用到?
- Spring 的表达式解析:#{}
- Thymeleaf 等模板引擎的语法解析
- 编译原理
Spring 框架中 SpelExpressionParser 就使用到解释器模式


# 注意事项和细节
- 当有一个语言需要解释执行,可将该语言中的句子表示为一个抽象语法树,就可以考虑使用解释器模式,让程 序具有良好的扩展性
- 应用场景:编译器、运算表达式计算、正则表达式、机器人等
- 使用解释器可能带来的问题:解释器模式会引起类膨胀、解释器模式采用递归调用方法,将会导致调试非常复杂、效率可能降低.
编辑 (opens new window)
上次更新: 2023/12/13, 06:06:02