23种设计模式(C++)之 解释器(Interpreter)模式
意图
给定一个语言,定义它的文法的一种表示,并定义一个解释器,这个解释器使用该表示来解释语言中的句子。
适用性
当有一个语言需要解释执行,并且你可将该语言中的句子表示为一个抽象语法树时,可使用解释器模式。而当存在以下情况时该模式效果最好:
- 该文法简单。对于复杂的文法,文法的类层次变得庞大而无法管理。(此时语法分析程序生成器这样的工具是更好的选择,它们无需构建抽象语法树即可解释表达式,这样可以节省空间和时间)
- 效率不是一个关键问题。最高效的解释器通常不是通过直接解释语法分析树实现的,而是首先将他们转换成另外一种形式。(例如,正则表达式通常被转换成状态机)
场景
比如查看指定产品是否存在,查看句子是否合理,四则运算,编译器等等。
角色
- AbstractExpression
- 声明一个抽象的解释操作,这个接口为抽象语法树中所有节点所共享
- TerminalExpression (终结符表达式)
- 实现与文法中的终结符相关联的解释操作
- 一个句子中的每个终结符需要该类的一个实例
- NonterminalExpression (非终结符表达式)
- 对文法中的每一条规则R ::=R1R2…Rn都需要一个非终结符表达式
- 为从R1 到Rn的每个符号都维护一个AbstractExpression类型的实例变量
- 为文法中的非终结符实现解释操作。(解释一般要递归地调用表示R1到Rn的那些对象的解释操作)
- Context(上下文)
- 包含解释器之外的一些全局信息
- Client
- 构建表示该文法定义的语言中一个特定的句子的抽象语法树。该抽象语法树由NonterminalExpression和TerminalExpression的实例装配而成。
- 调用解释操作
实例
以解释“颜色+车”为例:
- 创建表达式接口
class Express
{
public:
virtual bool interpret(string info) = 0;
};
- 创建终结符表达式
class TerminalExpress : public Express
{
private:
vector<string > names;
public:
TerminalExpress(vector<string > names)
{
this->names = names;
}
bool interpret(string info)
{
vector<string >::iterator it;
for (it = this->names.begin(); it != this->names.end();)
{
if (info.find(*it) == string::npos)
{
++it;
}
else
{
return true;
}
}
return false;
}
};
- 创建非终结符表达式
class AndTerminalExpress : public Express
{
private:
Express* express1;
Express* express2;
public:
AndTerminalExpress(Express* express1, Express* express2)
{
this->express1 = express1;
this->express2 = express2;
}
bool interpret(string info)
{
return this->express1->interpret(info) && this->express2->interpret(info);
}
};
- 创建上下文类
class Context
{
private:
Express* andExpress;
public:
Context()
{
vector<string> color = { "blue", "black", "white" };
vector<string> car = { "electricCar","oilCar" };
Express* colorExpress = new TerminalExpress(color);
Express* carExpress = new TerminalExpress(car);
this->andExpress = new AndTerminalExpress(colorExpress, carExpress);
}
void checkIfExist(string info)
{
if (this->andExpress->interpret(info))
{
cout << info + " exists." << endl;
}
else
{
cout << "Sorry, " + info + " doesn't exist." << endl;
}
}
};
- 创建客户类
int main()
{
Context* context = new Context();
context->checkIfExist("blue oilCar");
context->checkIfExist("yellow oilCar");
}
- 结果
blue oilCar exists.
Sorry, yellow oilCar doesn't exist.