意图:给定一个语言,定义它的文法的一种表示,并定义一个解释器,这个解释器适用该标识来解释语言中的句子。
动机:如果一种特定类型的问题发生的频率足够高,那么可能就值得将该问题的各个实例表述为一个简单语言中的句子。这样就可以构建一个解释器,该解释器通过解释这些句子来解决该问题。
例如:搜索匹配一个模式的字符串是一个常见的问题。正则表达式是描述字符串模式的一种标准语言。与其为每一个模式都构造一个特定的算法,不如使用一种通用的搜索算法来解释执行一个正则表达式,该正则表达式定义了待匹配字符串的集合。
解释器模式描述了如何为简单的语言定义一个文法,如何在该语言中表示一个句子,以及如何解释这些句子。即上面例子,本设计模式描述如何为正则表达式定义一个文法,如何表示一个特定的正则表达式,以及如何解释这个正则表达式。
适用性:
当一个语言需要解释执行,并且可将该语言中的句子表示为一个抽象的语树时,可使用解释器模式。当存在以下情况时,该模式效果最好:
1 该文法简单。对于复杂的文法,文法的类层次变得庞大而无法管理。此时语法分析程序生成器这样的工具是更好的选择。它们无需构建抽象语法树即可解释表达式,这样可以节省空间而且还能节省时间。
2 效率不是一个关键问题。最高效的解释器通常不是通过直接解释语法分析树实现的,而是先将它们转换成另一种形式。例如正则表达式通常被转换成状态机。但即使在这种情况下,转换器仍可用解释器模式实现,该模式仍然有用。
结构:
参与者:
AbstractExpression(抽象表达式)
声明一个抽象的解释操作,这个接口为抽象语法树中所有的节点所共享。
TerminalExpression(终结符表达式)
实现与文法中的终结符相关联的解释操作。一个句子中的每个终结符需要该类的一个实例。
NonterminalExpression(非终结符表达式)
对文法中的每一条规则 R::=R1R2…Rn都需要一个NonterminalExpression类。
为从R1到Rn的每个符号都维护一个AbstractExpression类型的实例变量。
为文法中的非终结符实现解释操作。解释一般要递归地调用表示R1到Rn的那些对象的解释操作。
Context(上下文):包含解释器外的一些全局信息
Client(客户):
构建表示该文发定义的语句中一个特定的句子的抽象语法树。该抽象语法树由NonterminalExpression和TerminalExpression的实例装配而成。
调用解释操作。
协作:
Client构建一个句子,它是NonterminalExpression和TerminalExpression的实例的一个抽象语法树,然后初始化上下文并调用解释操作。
每一个非终结符表达式节点定义相应子表达式的解释操作。而各终结符表达式的解释操作构成了递归的基础。
每一节点的解释操作用上下文来存储和访问解释器的状态。
效果:
有如下优点和不足:
1 易于改变和扩展文法;2 也易于实现文法 3 复杂的文法难以维护 4 增加了新的解释表达式的方式。
实现:
1 创建抽象语法树 2 定义解释操作 3 与Flyweight模式共享终结符
已知应用:解释器模式在OO语言中的编译器中得到了广泛的应用。
相关模式:
Composite:抽象语法树是一个复合模式的实例
Flyweight模式:说明了如何在抽象语法树中共享终结符
Iterator:解释器可用一个迭代器遍历该结构
Visitor:可用来在一个类中维护抽象语法树中的各节点的行为
代码(有问题,Context类和Constant类实现有些问题-_-):
//解释器模式
#include <iostream>
#include <cstring>
using namespace std;
class Context;
//为所有定义一个布尔表达式的类定义一个接口
class BooleanExp {
public:
BooleanExp() {}
virtual ~BooleanExp() {}
virtual bool Evaluate(Context&) = 0;
virtual BooleanExp* Replace(const char*, BooleanExp&) = 0;
virtual BooleanExp* Copy() const = 0;
};
class VariableExp;
//定义从变量到布尔值的一个映射,布尔值用true和false表示
class Context
{
public:
bool Lookup(const char* name) const
{
return true;
}
void Assign(VariableExp* var, bool b)
{
}
};
//表示一个有名变量
class VariableExp : public BooleanExp
{
public:
//将变量的名字作为参数
VariableExp(const char* name, bool b = true) : boolValue(b)
{
_name = new char[strlen(name)+1];
strcpy(_name, name);
}
virtual ~VariableExp()
{
delete [] _name;
}
//求一个变量的值,返回它在当前上下文中的值
bool Evaluate(Context& aContext)
{
return aContext.Lookup(_name);
}
//用表达式替换一个变量,检查该替换变量是否就是本对象代表的变量
BooleanExp* Replace(const char* name, BooleanExp& exp)
{
if (strcmp(name, _name) == 0)
return exp.Copy();
else
return new VariableExp(name);
}
//拷贝一个变量返回一个新的VariableExp
BooleanExp* Copy() const
{
return new VariableExp(_name);
}
private:
char* _name;
};
//AndExp表示由两个布尔表达式与操作得到的表达式
class AndExp : public BooleanExp
{
public:
AndExp(BooleanExp* op1, BooleanExp* op2)
: _operand1(op1), _operand2(op2)
{
}
//一个AndExp的值是求它的两个操作数的值的逻辑“与”
bool Evaluate(Context& aContext)
{
return _operand1->Evaluate(aContext) &&
_operand2->Evaluate(aContext);
}
//Copy和Replace操作递归调用它的操作数的Copy和Replace操作
BooleanExp* Copy() const
{
return new AndExp(_operand1->Copy(), _operand2->Copy());
}
BooleanExp* Replace(const char* name, BooleanExp& exp)
{
return new AndExp(
_operand1->Replace(name, exp), _operand2->Replace(name, exp));
}
private:
BooleanExp* _operand1;
BooleanExp* _operand2;
};
//OrExp表示由两个布尔表达式或操作得到的表达式
class OrExp : public BooleanExp
{
public:
OrExp(BooleanExp* op1, BooleanExp* op2)
: _operand1(op1), _operand2(op2)
{
}
//一个OrExp的值是求它的两个操作数的值的逻辑"或”
bool Evaluate(Context& aContext)
{
return _operand1->Evaluate(aContext) &&
_operand2->Evaluate(aContext);
}
//Copy和Replace操作递归调用它的操作数的Copy和Replace操作
BooleanExp* Copy() const
{
return new OrExp(_operand1->Copy(), _operand2->Copy());
}
BooleanExp* Replace(const char* name, BooleanExp& exp)
{
return new OrExp(
_operand1->Replace(name, exp), _operand2->Replace(name, exp));
}
private:
BooleanExp* _operand1;
BooleanExp* _operand2;
};
//NotExp表示一个表达式非操作得到的结果
class NotExp : public BooleanExp
{
public:
NotExp(BooleanExp* op) : _operand(op)
{
}
//一个NotExp的值是求它的两个操作数的值的逻辑“与”
bool Evaluate(Context& aContext)
{
return ~(_operand->Evaluate(aContext));
}
//Copy和Replace操作递归调用它的操作数的Copy和Replace操作
BooleanExp* Copy() const
{
return new NotExp(_operand->Copy());
}
BooleanExp* Replace(const char* name, BooleanExp& exp)
{
return new NotExp(_operand->Replace(name, exp));
}
private:
BooleanExp* _operand;
};
//表示布尔常量
class Constant : public BooleanExp
{
public:
Constant(bool b) : cc(b)
{}
bool Evaluate(Context& aContext)
{
return cc;
}
//Copy和Replace操作递归调用它的操作数的Copy和Replace操作
BooleanExp* Copy() const
{
return new Constant(cc);
}
BooleanExp* Replace(const char* name, BooleanExp& exp)
{
return new Constant(true);
}
private:
bool cc;
};
int main()
{
//求解bool表达式:(true and x) or (y and (not x)),x,y被赋值为true或false
BooleanExp* expression;
Context context;
VariableExp* x = new VariableExp("X");
VariableExp* y = new VariableExp("Y");
expression = new OrExp(
new AndExp(new Constant(true), x),
new AndExp(y, new NotExp(x))
);
context.Assign(x, false);
context.Assign(y, true);
bool result = expression->Evaluate(context);
cout << result << endl;
//替换y表达式
VariableExp* z = new VariableExp("Z");
NotExp not_z(z);
BooleanExp* replacement = expression->Replace("Y", not_z);
context.Assign(z, true);
cout << replacement->Evaluate(context); << endl;
system("pause");
return 0;
}