解释器模式(行为型)

前言


有时候,我们想用一些简单的语言来实现一些特点的操作,只要向计算机输入一个特定的句子,能够按照预定的文法规则对其进行解释。如一个简单的加减法解释器,只要输入一个加减法表达式,他就能计算出表达式的结果。像这种设计自定义的简单语言文法的功能可以采用解释器模式来实现。

解释器模式


意图

给定一个语言,定义它的文法的一种表示,并定义一个解释器,这个解释器使用该表示来解释语言中的句子

解释器模式描述了如何为简单的语言定义一个文法,如何在该语言中表示一个句子,以及如何解释这些句子
在解释器模式中还可以通过一种称之为抽象语法树(AST)的图形方式来直观地表示语言的构成,每一颗抽象语法树对应一个语言实例。通常,终结符表达式类的实例作为树的叶子节点,而非终结符表达式类的实例作为非叶子节点,它们可以将终结符表达式类的实例以及包含终结符和非终结符实例的子表达式作为其子节点
非终结符表达式:它的组成元素仍然可以是表达式,可以进一步分解
终结符表达式:它的组成元素是最基本的语言单位,不能再进行分解

参与者

  • AbstractExpression
    抽象表达式,声明了抽象的解释操作,他是所有终结符表达式和非终结符表达式的公共父类

  • TerminalExpression
    抽象表达式的子类,实现了与文法中的终结符相关联的解释操作,在句子中的每一个终结符都是该类的一个实例
    通常在一个解释器模式中只有少数几个终结符表达式类,它们的实例可以通过非终结符表达式组成较为复杂的句子

  • NonterminalExpression
    非终结符表达式也是抽象表达式的子类,它实现了文法中非终结符的解释操作
    由于在非终结符表达式中可以包含终结符表达式,也可以继续包含非终结符表达式,因此其解释操作一般通过递归的方式来完成

  • Context
    环境类又称为上下文类,它用于存储解释器之外的一些全局信息,通常它临时存储了需要解释的语句
    这个角色的任务一般是也用来存放文法中各个终结符所对应的具体值,比如R=R1+R2,我们给R1赋值100,给R2赋值200。这些信息需要存放到环境角色中,很多情况下我们使用Map来充当环境角色就足够了

模式结构

interpreter

代码实现

1.首先定义抽象的表达式AbstractExpression,并提供Interpreter()接口:

1
2
3
4
5
6
// Abstract Expression
class AbstractExpression
{
public:
virtual int Interpreter(Context ctx) = 0;
};

2.再定义AbstractExpression类的一个具体终结符表达式子类TerminalExpression,并实现其中的Interpreter()接口,该接口主要作用是返回一个操作数:

1
2
3
4
5
6
7
8
9
10
11
12
13
// Terminal Expression
class TerminalExpression : public AbstractExpression
{
private:
int m_Value;
public:
TerminalExpression(int value) : m_Value(value) {};
public:
virtual int Interpreter(Context ctx)
{
return m_Value;
}
};

3.分别在定义两个具体的+-操作符非终结符表达式类PlusNonterminalExpressionSubNonterminalExpression类,并分别实现其Interpreter()接口,主要通过递归调用来实现:

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
// NonTerminal Expression 2: Plus ('+')
class PlusNonterminalExpression : public AbstractExpression
{
private:
AbstractExpression *m_pLeftExpr;
AbstractExpression *m_pRightExpr;
public:
PlusNonterminalExpression(AbstractExpression *pLeft, AbstractExpression *pRight) : m_pLeftExpr(pLeft), m_pRightExpr(pRight) {};
public:
virtual int Interpreter(Context ctx)
{
return m_pLeftExpr->Interpreter(ctx) + m_pRightExpr->Interpreter(ctx);
//调用两个操作数的Interpreter接口
}
};

// NonTerminal Expression 1: Sub ('-')
class SubNonterminalExpression : public AbstractExpression // 默认是私有继承
{
private:
AbstractExpression *m_pLeftExpr;
AbstractExpression *m_pRightExpr;
public:
SubNonterminalExpression(AbstractExpression *pLeft, AbstractExpression *pRight) : m_pLeftExpr(pLeft), m_pRightExpr(pRight) {};
public:
virtual int Interpreter(Context ctx)
{
return m_pLeftExpr->Interpreter(ctx) - m_pRightExpr->Interpreter(ctx); //调用两个操作数的Interpreter接口
}
};

4.上下文环境类Context,主要是存储解释器之外的一些全局信息:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
// Context,一般使用map或list实现
class Context
{
private:
map<string, int> m_mapValue;
public:
void AddValue(string key, int value)
{
m_mapValue.insert(make_pair(key, value));
}
int GetValue(string key)
{
return m_mapValue[key];
}
};

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
void InterpreterTest_Computaion()
{
Context ctx;
ctx.AddValue("x", 5);
ctx.AddValue("y", 8);
ctx.AddValue("z", 7);

// Create Terminal Expression
AbstractExpression *pTE1 = new TerminalExpression(ctx.GetValue("x"));
AbstractExpression *pTE2 = new TerminalExpression(ctx.GetValue("y"));
AbstractExpression *pTE3 = new TerminalExpression(ctx.GetValue("z"));

AbstractExpression *pPNE = new PlusNonterminalExpression(pTE1, pTE2); //pPNE: PTE1->Interpreter() + pTE2->Intepreter()
AbstractExpression *pSNE = new SubNonterminalExpression(pPNE, pTE3); // pSNE: PNE->Interpreter() - pTE3->Intepreter()
AbstractExpression *pPNE2 = new PlusNonterminalExpression(pSNE, pPNE); //pPNE2: PSNE->Interpreter() + pPNE->Intepreter()

cout << "The Final Result of Express : x(5) + y(8) is " << pPNE->Interpreter(ctx) << endl;
cout << "The Final Result of Express : x(5) + y(8) - z(7) is " << pSNE->Interpreter(ctx) << endl;
cout << "The Final Result of Express : x(5) + y(8) - z(7) + x(5) + y(8) is " << pPNE2->Interpreter(ctx) << endl;

SAFE_RELASE_POINTER(pTE1);
SAFE_RELASE_POINTER(pTE2);
SAFE_RELASE_POINTER(pTE3);
SAFE_RELASE_POINTER(pPNE);
SAFE_RELASE_POINTER(pSNE);
SAFE_RELASE_POINTER(pPNE2);
}

6.运行结果:

The Final Result of Express : x(5) + y(8) is 13
The Final Result of Express : x(5) + y(8) - z(7)  is 6
The Final Result of Express : x(5) + y(8) - z(7) + x(5) + y(8) is 19

使用场景

  • 有一个简单的语法规则,比如一个sql语句,如果我们需要根据sql语句进行rm转换,就可以使用解释器模式来对语句进行解释
  • 一些重复发生的问题,比如加减乘除四则运算,但是公式每次都不同,有时是a+b-cd,有时是ab+c-d,等等等等个,公式千变万化,但是都是由加减乘除四个非终结符来连接的,这时我们就可以使用解释器模式

优缺点

  • 优点
    • 解释器是一个简单的语法分析工具,它最显著的优点就是扩展性,修改语法规则只需要修改相应的非终结符就可以了,若扩展语法,只需要增加非终结符类就可以了
  • 缺点
    • 解释器模式会引起类的膨胀,每个语法都需要产生一个非终结符表达式,语法规则比较复杂时,就可能产生大量的类文件,为维护带来非常多的麻烦
    • 由于采用递归调用方法,每个非终结符表达式只关心与自己相关的表达式,每个表达式需要知道最终的结果,必须通过递归方式,无论是面向对象的语言还是面向过程的语言,递归都是一个不推荐的方式。由于使用了大量的循环和递归,效率是一个不容忽视的问题

解释器模式具体实例


机器人控制问题

该机器人控制程序中包含一些简单的英文控制指令,如”down run 10 and left move 20”表示快速向下移动10cm,并向左移动20cm,具体文法如下:

  • 每一个指令对应一个表达式(expression),该表达式可以是简单表达式也可以是复合表达式,
  • 每一个简单表达式由方向(direction),移动方式(action)和移动距离(distance)三部分组成
  • 其中移动方向包括上(up)、下(down)、左(left)、右(right);
  • 移动方式包括移动(move)和快速移动(run);
  • 移动距离为一个正整数
  • 两个表达式之间可以通过与(and)连接,形成复合(composite)表达式

代码实现

1.定义抽象的AbstractControlExpression类,并提供interpreter接口:

1
2
3
4
5
6
// abstract expr
class AbstractControlExpression
{
public:
virtual string interpreter(void) = 0;
};

2.分别定义抽象表达式AbstractControlExpression的终结表达式子类DirectionExpressionActionExpressionDistanceExpression:

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
// 方向终结符表达式:把英文的方向解释为中文
class DirectionExpression : public AbstractControlExpression
{
public:
DirectionExpression(string direction) : _direction(direction) {};
string interpreter(void)
{
if (_direction.compare("up"))
{
return "向上";
}
else if (_direction.compare("down"))
{
return "向下";
}
else if (_direction.compare("left"))
{
return "向左";
}
else if (_direction.compare("right"))
{
return "向右";
}
else
{
return "无效的命令";
}
}
private:
string _direction;
};

// 动作终结符表达式:把英文的动作解释为中文
class ActionExpression : public AbstractControlExpression
{
public:
ActionExpression(string action) : _action(action) {};
string interpreter(void)
{
if (_action.compare("run"))
{
return "快速移动";
}
else if (_action.compare("move"))
{
return "移动";
}
else
{
return "无效的命令";
}
}
private:
string _action;
};

// 距离终结符表达式
class DistanceExpression : public AbstractControlExpression
{
public:
DistanceExpression(string distance) : _distance(distance) {};
string interpreter(void)
{
return _distance + "厘米";
}
private:
string _distance;
};

3.分别定义抽象表达式AbstractControlExpression的非终结表达式子类SimpleSentenceExpressionAndSentenceExpression:

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
// 简单句子非终结符表达式
class SimpleSentenceExpression : public AbstractControlExpression
{
public:
SimpleSentenceExpression(AbstractControlExpression *direction, AbstractControlExpression *action, AbstractControlExpression *distance):
_direction(direction), _action(action), _distance(distance) {};
public:
string interpreter(void)
{
return (_direction->interpreter() + _action->interpreter() + _distance->interpreter()); //调用终结符的interpreter
}
private:
AbstractControlExpression *_direction;
AbstractControlExpression *_action;
AbstractControlExpression *_distance;
};

// And句子非终结符表达式
class AndSentenceExpression : public AbstractControlExpression
{
public:
AndSentenceExpression(AbstractControlExpression *leftSentence, AbstractControlExpression* rightSentence):
_leftSentence(leftSentence), _rightSentence(rightSentence) {};
public:
string interpreter(void)
{
return (_leftSentence->interpreter() + "并且" + _rightSentence->interpreter());
}
private:
AbstractControlExpression *_leftSentence;
AbstractControlExpression *_rightSentence;
};

4.测试解释器模式:

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
//Robot Control Test
void InterpreterTest_RobotControl(void)
{
string finalRes;
AbstractControlExpression *direction = new DirectionExpression("down");
AbstractControlExpression *action = new ActionExpression("move");
AbstractControlExpression *distance = new DistanceExpression("100");

AbstractControlExpression *simple_sentence = new SimpleSentenceExpression(direction, action, distance);

AbstractControlExpression *direction2 = new DirectionExpression("up");
AbstractControlExpression *action2 = new ActionExpression("run");
AbstractControlExpression *simple_sentence2 = new SimpleSentenceExpression(direction2, action2, distance);

AbstractControlExpression *complex_sentence = new AndSentenceExpression(simple_sentence, simple_sentence2);
finalRes = complex_sentence->interpreter();
cout << finalRes << endl;

SAFE_RELASE_POINTER(direction);
SAFE_RELASE_POINTER(action);
SAFE_RELASE_POINTER(distance);
SAFE_RELASE_POINTER(simple_sentence);

SAFE_RELASE_POINTER(direction2);
SAFE_RELASE_POINTER(action2);
SAFE_RELASE_POINTER(simple_sentence2);
SAFE_RELASE_POINTER(complex_sentence);
}

5.运行结果:

向上快速移动100厘米并且向下移动100厘米