设计模式-解释器模式

解释器模式(Interpreter Pattern): 给定一个语言, 定义它的文法的一种表示, 并定义一个解释器, 这个解析器使用该来解释语言中的句子.

设计模式-概述

解析器模式使用频率较低, 它描述了如何使用面向对象语言构成一个语言解析器.

结构

解析器模式包含4个角色:

  1. 抽象表达式(AbstractExpression): 所有终结符表达式和非终结符表达式的公共父类.
  2. 终结符表达式(TerminalExpression): 抽象表达式的子类, 实现了文法中的终结符相关解析操作, 每一个终结符对应一个该类的实例.
  3. 非终结符表达式(NonterminalExpression): 抽象表达式的子类, 实现了文法中非终结符的解释操作, 非终结符表达式包含了其他终结符表达式和非终结符表达式, 因此通常使用递归来实现.
  4. 环境类(Context): 存储了解析器的上下文, 包含需要解析的语句.

interpreter-1.png

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
@@startuml interpreter-1
!include common.cuml

Class(Context,"环境类") {
}

Class(AbstractExpression,"抽象表达式") {
+ interpret(Context ctx) : void
}

Class(TerminalExpression,"终结符表达式") {
+ interpret(Context ctx) : void
}

Class(NonterminalExpression,"非终结符表达式") {
+ interpret(Context ctx) : void
}

Class(Client,"客户端") {
}

Client .right.> AbstractExpression
Client .right.> Context
AbstractExpression ..> Context
TerminalExpression -up-|> AbstractExpression
NonterminalExpression -up-|> AbstractExpression
NonterminalExpression o--> AbstractExpression

@@enduml

代码实现

  1. 定义TerminalExpression输出A, NonterminalExpression输出其内部包含的左右内容中间-分割.
  2. 使用Context定义好规则.
  3. 实例化一个NonterminalExpression对象.
  4. 调用其interpret方法, 返回结果.

非终结符表达式 和 终结符表达式 可以有多种不同实现, 以应对不同的语法结构.

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
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
package com.yuda.desigmode.main4;

import java.util.HashMap;

/**
* @author canyu
* @create_date 2020/11/25 21:19
*/
public class Main4 {
public static void main(String[] args) {
Context context = new Context();
context.assign("TerminalExpression", "A");
context.assign("NonterminalExpression", "B");
AbstractExpression TerminalExpressionA = new TerminalExpression();
AbstractExpression TerminalExpressionB = new TerminalExpression();
AbstractExpression NonterminalExpression = new NonterminalExpression(TerminalExpressionA, TerminalExpressionB);
System.out.println("结果为:" + NonterminalExpression.interpret(context));
}
}

class Context {
private HashMap<String, String> map = new HashMap<>();

public void assign(String key, String value) {
map.put(key, value);
}

public String lookup(String key) {
return map.get(key);
}
}

abstract class AbstractExpression {
public abstract String interpret(Context context);
}

class TerminalExpression extends AbstractExpression {

@Override
public String interpret(Context context) {
// System.out.println("TerminalExpression.interpret");
System.out.printf("TerminalExpression输出: %s\n", context.lookup(this.getClass().getSimpleName()));
return context.lookup(this.getClass().getSimpleName());
}
}

class NonterminalExpression extends AbstractExpression {

private AbstractExpression left;
private AbstractExpression right;

public NonterminalExpression(AbstractExpression left, AbstractExpression right) {
this.left = left;
this.right = right;
}

@Override
public String interpret(Context context) {
// System.out.println("NonterminalExpression.interpret");
String interpret = left.interpret(context);
System.out.printf("NonterminalExpression: %s\n", context.lookup(this.getClass().getSimpleName()));
String interpret1 = right.interpret(context);
System.out.printf("NonterminalExpression: %s\n", context.lookup(this.getClass().getSimpleName()));
return interpret + "-" + interpret1;
}
}

结果输出:

1
2
3
4
5
TerminalExpression输出: A
NonterminalExpression: B
TerminalExpression输出: A
NonterminalExpression: B
结果为:A-A

使用场景

  1. 当语言的文法较为简单, 且执行效率不是关键问题时.
  2. 当问题重复出现, 且可以用一种简单的语言来进行表达时.
  3. 当一个语言需要解释执行, 并且语言中的句子可以表示为一个抽象语法树的时候.

具体应用

XML的文档解释: 基于DOM的XML分析器将一个XML文档转换成一个对象模型的集合.