20 【行为型】解释器模式 - Interpreter
通过解释器模式实现四则运算,具体要求:
输入表达式,比如a+b+c-d
基本介绍:
1、解释器模式(interpreter):给定一个语言,定义它的文法的一种表示,并定义一个解释器,这个解释器使用该表示来解释语言中的句子。
2、解释器模式需要解决的是,如果一种特定类型的问题发生的频率足够高,那么可能就值得将该问题的各个实例表述为一个简单语言中的句子。这样就可以构建一个解释器,该解释器通过解释这些句子来解决该问题;
3、在编译原理中,一个算数表达式通过语法分析器形成词法单元,词法分析器和语法分析器,都是解释器;
应用场景:
1、编译器,正则表达式,浏览器(解析html显示)、机器人等等
2、正则表达式就是它的一种应用,解释器为正则表达式定义了一个文法,如何表示一个特定的正则表达式,以及如何解释这个正则表达式;
原理类图:

角色及职责说明:
1、context:环境角色,还有解释器之外的全局信息;
2、abstractExpression:抽象表达式,声明一个抽象的解释操作,这个方法为抽象语法树中所有的节点所共享;
3、terminalExpression:为终结符表达式,实现与文法中的终结符相关的解释操作;
4、NonTerminalExpression:为非终结表达式,为文法中的非终结符实现解释操作;
5、说明:输入context和expression通过用户输入即可;
/*
* @Description:
* @Remark:
* @Author: whl
* @博客园: https://www.cnblogs.com/cnwhl/
* @Date: 2021-12-29 17:21:11
* @LastEditTime: 2021-12-30 20:15:00
*/
#include <stdlib.h>
#include <iostream>
#include <string>
#include <map>
using namespace std;
class Context;
/**
* @description: 抽象表达式类
* @Remark: 声明一个抽象解释操作,这个接口为抽象语法树中所有的接口所共享
*/
class AbstractExpression
{
public:
virtual int Interpret(Context* pContext, int& index) = 0;
};
/**
* @description: 上下文信息类
* @Remark: 提供设置表达式接口和计算接口
*/
class Context
{
public:
void SetExpression(char c,AbstractExpression* pExpr)
{
m_mapExpr[c] = pExpr;
}
// a + b - c + d
int Caculate(string expression){
m_res = 0;
m_expr = expression;
for(int i = 0; i < expression.size(); i++){
string expr;
switch(expression[i])
{
case '+':
{
auto it = m_mapExpr.find('+');
m_res = it->second->Interpret(this,i);
break;
}
case '-':
{
auto it = m_mapExpr.find('-');
m_res = it->second->Interpret(this,i);
break;
}
default:
{
expr = expression[i];
m_res += atoi(expr.c_str());
break;
}
}
}
return m_res;
}
int GetRes(){
return m_res;
}
int GetNum(int index){
char sz[4] = { 0 };
sz[0] = m_expr[index];
return atoi(sz);
}
private:
map<char,AbstractExpression*> m_mapExpr;
string m_expr;
int m_res;
};
/**
* @description: 具体表达式实现类
* @Remark: 实现加法操作
*/
class AddExpression: public AbstractExpression
{
public:
int Interpret(Context* pContext, int& index){
cout << "Add Expression " << endl;
return pContext->GetRes() + pContext->GetNum(++index);
}
};
/**
* @description: 具体表达式实现类
* @Remark: 实现减法操作
*/
class SubExpression: public AbstractExpression
{
public:
int Interpret(Context* pContext, int& index){
cout << "Sub Expression " << endl;
return pContext->GetRes() - pContext->GetNum(++index);
}
};
/**
* @description: 计算表达式的函数
* @Remark: 为了跟上述类做对比
* @param {string} expression 表达式
* @return int
*/
// a + b - c + d
int Caculate(string expression)
{
int res = 0;
for(int i = 0; i < expression.size(); i++){
string expr;
switch(expression[i])
{
case '+':
expr = expression[++i];
res += atoi(expr.c_str());
break;
case '-':
expr = expression[++i];
res -= atoi(expr.c_str());
break;
default:
expr = expression[i];
res += atoi(expr.c_str());
break;
}
}
return res;
}
int main()
{
int res = Caculate("1+2-3+4");
cout << "res = " << res << endl;
AddExpression* pAddExpr = new AddExpression();
SubExpression* pSubExpr = new SubExpression();
Context* pContext = new Context();
pContext->SetExpression('+',pAddExpr);
pContext->SetExpression('-',pSubExpr);
res = pContext->Caculate("1+2-3+4");
cout << "res = " << res << endl;
return 0;
}注意事项及优缺点:
1、可能会引起类的膨胀,递归调用方法,导致复杂,效率低下;
2、优点:
容易地改变和扩展文法,因为该模式使用类来表示文法规则,你可使用继承来改变或扩展该文法。也比较容易实现文法,因为定义抽象语法树中各个节点的类的实现大体类似,这些类都易于直接编写;
3、缺点:
解释器模式为文法中的每一条规则至少定义了一个类,因此包含许多规则的文法可能难以管理和维护。建议当文法非常复杂时,使用其他的技术如:语法分析程序、编译器生成器 来处理;

浙公网安备 33010602011771号