解释器模式
书面定义: 给定一个语言,定义它的文法的一种表示,并定义一个解释器,这个解释器使用该表示来解释语言中的句子。
解释器这个名词对于程序员来讲并不陌生,例如编译原理中,一个算术表达式通过词法分析器形成词法单元,而后这些词法单元再通过语法分析器构建语法分析树。最终形成一棵抽象的语法分析树
说一种比较易懂的理解,以正则表达式为例,它就是解释器模式的一种应用,解释器为正则表达式定义了文法,如何表示一个特定的正则表达式,以及如何解释这个表达式。
语法层面的说法个人觉得可以理解为充分利用多态的特性将各个解释器串联起来完成对应表达式的完成解释
# 优缺点
优点很明显,当我们语法变更的时候只需要增删对应的语法解释器即可。这也就意味着它的扩展性良好
缺点
容易引起类膨胀
解释器模式采用递归调用方法,将导致调试的难度增加
使用大量的循环和递归,效率相对比较低
正如前文提到的,设计模式、算法和数据结构没有优劣之分,仅仅是适用的场景不同
它的基础类图如下
类图是我从其他文档上摘抄过来的,但是原理是相通的
# 代码实现
之前在网上看到一个关于适用解释器模式实现加减运算的案例,只是针对设计模式的学习增加了成本,我这里还是采用上面类图的方式先跑通再深入。同时博客的地址我也贴出来有兴趣的可以去看看
博客地址:https://www.cnblogs.com/adamjwh/p/10938852.html
program Interpreter;
{$APPTYPE CONSOLE}
{$R *.res}
// 解释器模式
uses
System.Generics.Collections, System.SysUtils;
type
// 类的向前声明,因为TContext中引用了TExpression而TExpression又在TContext之后定义
TExpression = class;
// 待解释的上下文(或者称为内容)
TContext = class
private
// 待解释内容
FContent: String;
FInterpretList: TList<TExpression>;
public
property Context: String read FContent write FContent;
// 覆盖父类的构造
constructor Create(); overload;
// 添加(指定解释器)
procedure AddInterpret(Expression: TExpression);
// 解释器列表
property InterpretList: TList<TExpression> read FInterpretList write FInterpretList;
end;
// 声明为抽象类(基础解释器),这种写法是我在一个开源项目中看到的
TExpression = class abstract
protected
// 编写为虚方法,便于将来重写
procedure Interpret(Context: TContext); virtual; abstract;
end;
TAdvanceExpression = class(TExpression)
public
// 重写核心的解释方法
procedure Interpret(Context: TContext); override;
end;
// 以类图为基准的代码编写
TSimpleExpression = class(TExpression)
public
// 重写核心的解释方法
procedure Interpret(Context: TContext); override;
end;
{ TAdvanceExpression }
procedure TAdvanceExpression.Interpret(Context: TContext);
begin
Writeln('这是高级解析器');
end;
{ TSimpleExpression }
procedure TSimpleExpression.Interpret(Context: TContext);
begin
Writeln('这是普通解析器');
end;
{ TContext }
procedure TContext.AddInterpret(Expression: TExpression);
begin
InterpretList.Add(Expression);
end;
constructor TContext.Create;
begin
inherited Create;
InterpretList := TList<TExpression>.Create();
end;
begin
try
var
Ctx := TContext.Create();
// 组装解释器,我的理解是形成所谓的解释器树
Ctx.AddInterpret(TSimpleExpression.Create());
Ctx.AddInterpret(TAdvanceExpression.Create());
// 执行解释
for var CtxInterpret in Ctx.InterpretList do begin
CtxInterpret.Interpret(Ctx);
end;
except
on E: Exception do Writeln(E.ClassName, ': ', E.Message);
end;
Readln;
end.
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
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