设计模式之解释器模式

释放双眼,带上耳机,听听看~!

0x01.定义与类型

  • 定义:给定一个语言,定义它的文法的一种表示,并定义一个解释器,这个解释器使用该表示来解释语言中的句子。
  • 为了解释一种语言,而为语言创建的解释器。
  • 类型:行为型
  • UML类图

设计模式之解释器模式

  • 一个解释器模式中包含的四种角色

  • 抽象(或接口)解释器(Interpreter):声明一个所有具体表达式都要实现的抽象接口(或者抽象类),接口中主要是一个interpret()方法,称为解释操作。具体解释任务由它的各个实现类来完成,具体的解释器分别由终结符解释器和非终结符解释器完成。

    • 终结符表达式(TerminalExpression):实现与文法中的元素相关联的解释操作,通常一个解释器模式中只有一个终结符表达式,但有多个实例,对应不同的终结符。终结符一半是文法中的运算单元,比如有一个简单的公式R=R1+R2,在里面R1和R2就是终结符,对应的解析R1和R2的解释器就是终结符表达式。
    • 非终结符表达式(NonterminalExpression):文法中的每条规则对应于一个非终结符表达式,非终结符表达式一般是文法中的运算符或者其他关键字,比如公式R=R1+R2中,+就是非终结符,解析+的解释器就是一个非终结符表达式。非终结符表达式根据逻辑的复杂程度而增加,原则上每个文法规则都对应一个非终结符表达式。
    • 环境角色(Context):这个角色的任务一般是用来存放文法中各个终结符所对应的具体值,比如R=R1+R2,我们给R1赋值100,给R2赋值200。这些信息需要存放到环境角色中,很多情况下我们使用Map来充当环境角色就足够了。

0x02.适用场景

  • 在某个特定类型问题发生频率足够高,需要自定义语法的场景。比如数据按照配置规则ETL!

0x03.优缺点

1.优点

  • 语法由很多类表示,容易改变及扩展此“语言”

2.缺点

  • 当语法规则数目太多时,增加了系统复杂度。

0x04.样例代码

使用解释器模式实现一个简单的语法 计算 **6 100 11 + *** 表达式,首先记录数值,然后按照顺序添加符号计算。
100 + 11
111 * 6
666

  • java代码实现


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
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
1/**
2 * 表达式定义接口
3 */
4public interface Interpreter {
5    int interpret();
6}
7
8/**
9 * 相加表达式
10 */
11public class AddInterpreter implements Interpreter {
12
13    private Interpreter firstExpression, secondExpression;
14
15    public AddInterpreter (Interpreter firstExpression, Interpreter secondExpression) {
16        this.firstExpression = firstExpression;
17        this.secondExpression = secondExpression;
18    }
19
20    @Override
21    public int interpret() {
22        return this.firstExpression.interpret() + this.secondExpression.interpret();
23    }
24
25    @Override
26    public String toString() {
27        return "+";
28    }
29}
30
31/**
32 * 相乘规则表达式
33 */
34public class MultiInterpreter implements Interpreter {
35
36    private Interpreter firstExpression, secondExpression;
37
38    public MultiInterpreter(Interpreter firstExpression, Interpreter secondExpression) {
39        this.firstExpression = firstExpression;
40        this.secondExpression = secondExpression;
41    }
42
43
44    @Override
45    public int interpret() {
46        return this.firstExpression.interpret() * this.secondExpression.interpret();
47    }
48
49    @Override
50    public String toString() {
51        return "*";
52    }
53}
54
55/**
56 * 数值型表达式
57 */
58public class NumberInterpreter implements Interpreter {
59
60    private int number;
61
62    public NumberInterpreter(int number) {
63        this.number = number;
64    }
65
66    public NumberInterpreter(String number){
67        this.number = Integer.parseInt(number);
68    }
69
70    @Override
71    public int interpret() {
72        return this.number;
73    }
74}
75
76/**
77 * 格式化表达式
78 */
79public class ExpressionParser {
80
81    private Stack<Interpreter> stack = new Stack<>();
82
83    public int parse (String expression) {
84        String[] itemArray = expression.split(" ");
85        for (String symbol : itemArray) {
86            if (!OperatorUtil.isOperator(symbol)) {
87                Interpreter numberExpression = new NumberInterpreter(symbol);
88                stack.push(numberExpression);
89                System.out.println(String.format("入栈: %d", numberExpression.interpret()));
90            } else {
91                //是运算符可以计算
92                Interpreter firstExpression = stack.pop();
93                Interpreter secondExpression = stack.pop();
94                System.out.println(String.format("出栈:%d 和 %d", firstExpression.interpret(),
95                        secondExpression.interpret()));
96                Interpreter operator = OperatorUtil.getExpression(firstExpression, secondExpression, symbol);
97                System.out.println(String.format("应用运算符: %s", operator));
98                int result = operator.interpret();
99                NumberInterpreter numberInterpreter = new NumberInterpreter(result);
100                stack.push(numberInterpreter);
101                System.out.println(String.format("阶段结果入栈: %d", result));
102            }
103        }
104        return stack.pop().interpret();
105    }
106}
107
108/**
109 * 工具类
110 */
111public class OperatorUtil {
112
113    public static boolean isOperator(String symbol) {
114        return (symbol.equals("+") || symbol.equals("*"));
115    }
116
117    public static Interpreter getExpression(Interpreter first,
118                                            Interpreter second,
119                                            String symbol) {
120        switch (symbol) {
121            case "+":
122                return new AddInterpreter(first, second);
123            case "*":
124                return new MultiInterpreter(first, second);
125            default:
126                return null;
127        }
128    }
129}
130
131
  • 测试与应用


1
2
3
4
5
6
7
8
9
10
11
12
13
14
1/**
2 * 测试类
3 */
4public class Test {
5
6    public static void main(String[] args) {
7        String input = "6 100 11 + *";
8        ExpressionParser parser = new ExpressionParser();
9        int result = parser.parse(input);
10        System.out.println("解释器运算结果:" + result);
11    }
12}
13
14
  • 输出日志


1
2
3
4
5
6
7
8
9
10
11
12
1入栈: 6
2入栈: 100
3入栈: 11
4出栈:11 和 100
5应用运算符: +
6阶段结果入栈: 111
7出栈:111 和 6
8应用运算符: *
9阶段结果入栈: 666
10解释器运算结果:666
11
12
  • 代码对应的UML类图

设计模式之解释器模式

在样例中:AddInterpreter和MultiInterpreter为终结表达式,NumberInterpreter为非终结表达式,ExpressionParser为环境角色。

0x05.相关设计模式

  • 解释器模式和适配器模式

  • 适配器模式不需要先知道适配的规则

    • 解释器模式要预先知道语法规则

0x06.源码中的解释器模式

  • Pattern
  • Spring SpelExpressionParse

0x07.代码地址

0x08.推荐阅读

给TA打赏
共{{data.count}}人
人已打赏
安全运维

基于spring boot和mongodb打造一套完整的权限架构(二)【MAVEN依赖以及相应配置】

2021-12-11 11:36:11

安全运维

Ubuntu上NFS的安装配置

2021-12-19 17:36:11

个人中心
购物车
优惠劵
今日签到
有新私信 私信列表
搜索