Interpreter模式

情景引入

学习到这里,大家应该已经掌握了不少设计模式。设计模式的目的之一就是提高类的可复用
性。可复用性是指不用做太大修改(甚至是不做任何修改)就可以在多种应用场景使用之前编写
的类。

在本章中,我们将学习Interpreter模式。
在Interpreter模式中,程序要解决的问题会被用非常简单的“迷你语言”表述出来,即用“迷
你语言”编写的“迷你程序”把具体的问题表述出来。迷你程序是无法单独工作的,我们还需要用
Java语言编写一个负责“翻译”( interpreter )的程序。翻译程序会理解迷你语言,并解释和运行迷
你程序。这段翻译程序也被称为解释器。这样,当需要解决的问题发生变化时,不需要修改Java语
言程序,只需要修改迷你语言程序即可应对。

下面,我们用图示展示一下当问题发生变化时,需要哪个级别的代码。使用Java语言编程时,
需要修改的代码如图23-1所示。虽然我们希望需要修改的代码尽量少,但是多多少少都必须修改
Java代码。

但是,在使用Interpreter模式后,我们就无需修改Java程序,只需修改用迷你语言编写的迷你
程序即可(图23-2)。
图23-2

示例程序

功能描述

使用迷你语言控制玩具车
语法树

类的一览表

名字 说明
Node 表示语法树“节点”的类
ProgramNode 对应的类
CommandListNode 对应 的类
CommandNode 对应 的类
RepeatCommandNode 对应 的类
PrimitiveCommandNode 对应 的类
Context 表示语法解析上下文的类
ParseException 表示语法解析中可能会发生的异常的类
Main 测试程序行为的类

UML

解释器模式

主要代码

Node 类

1
2
3
public abstract class Node {
public abstract void parse(Context context) throws ParseException;
}

ProgramNode 类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
public class ProgramNode extends Node{
private Node commandListNode;
@Override
public void parse(Context context) throws ParseException {
context.skipToken("Program");
commandListNode = new CommandListNode();
commandListNode.parse(context);
}

@Override
public String toString() {
return "ProgramNode{" +
"commandListNode=" + commandListNode +
'}';
}
}

CommandListNode 类

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
public class CommandListNode extends Node{
private ArrayList list = new ArrayList();
@Override
public void parse(Context context) throws ParseException {
while(true){
if(context.currentToken() == null){
throw new ParseException("Missing 'END'");
}else if(context.currentToken().equals("end")){
context.skipToken("end");
break;
}else{
Node commandNode = new CommandNode();
commandNode.parse(context);
list.add(commandNode);
}
}
}

@Override
public String toString() {
return "CommandListNode{" +
"list=" + list +
'}';
}
}

CommandNode 类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
public class CommandNode extends Node {
private Node node;

@Override
public void parse(Context context) throws ParseException {
if (context.currentToken().equals("repeat")) {
node = new RepeatCommandNode();
node.parse(context);
} else {
node = new PrimitiveCommandNode ();
node.parse(context);
}
}

@Override
public String toString() {
return "CommandNode{" +
"node=" + node.toString() +
'}';
}
}

RepeatCommandNode 类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
public class RepeatCommandNode extends Node {
private int number;
private Node commandListNode;

@Override
public void parse(Context context) throws ParseException {
context.skipToken(" repeat");
number = context.currentNumber();
context.nextToken();
commandListNode = new CommandListNode();
commandListNode.parse(context);

}

@Override
public String toString() {
return "RepeatCommandNode{" +
"number=" + number +
", commandListNode=" + commandListNode +
'}';
}
}

PrimitiveCommandNode 类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
public class PrimitiveCommandNode extends Node {
private String name;

@Override
public void parse(Context context) throws ParseException {
name = context.currentToken();
context.skipToken(name);
if (!name.equals("go") && !name.equals("right") && !name.equals("left")){
throw new ParseException(name +"is undefined") ;
}
}

@Override
public String toString() {
return "PrimitiveCommandNode{" +
"name='" + name + '\'' +
'}';
}
}

Context 类

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
public class Context {
private StringTokenizer tokenizer;
private String currentToken;

public Context(String text) {
tokenizer = new StringTokenizer(text);
nextToken();
}

public String nextToken() {
if (tokenizer.hasMoreTokens()) {
currentToken = tokenizer.nextToken();
} else {
currentToken = null;
}
return currentToken;
}

public String currentToken() {

return currentToken;
}

public void skipToken(String token) throws ParseException {
if (!token.equals(currentToken)) {
throw new ParseException("Warning:" + token + "is expected, but" + currentToken + "is found.");
}
nextToken();
}

public int currentNumber() throws ParseException {
int number = 0;
try {
number = Integer.parseInt(currentToken);
} catch (NumberFormatException e) {
throw new ParseException("Warning:" + e);
}
return number;
}
}

ParseException 类

1
2
3
4
5
public class ParseException extends Exception{
public ParseException(String msg){
super(msg);
}
}

Main 类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
public class Main {
public static void main(String[] args) {
try {
BufferedReader reader = new BufferedReader(new FileReader("program.txt"));
String text;
while ((text = reader.readLine()) != null) {
System.out.println("text = \"" + text + "\"");
Node node = new ProgramNode();
node.parse(new Context(text));
System.out.println("node =" + node);
}
reader.close();
} catch (Exception e) {
e.printStackTrace();
}
}
}

program.txt

1
2
3
4
5
6
program end
program go end
program go right go right go right go right end
program repeat 4 go right end end
program repeat 4 repeat 3 go right go left end right end end


Interpreter模式
http://lhystutest.top/2022/11/02/设计模式/interpreter 模式/Interpreter模式/
作者
lhy
发布于
2022年11月2日
许可协议