解释器模式
Given a language, define a representation for its grammar along with an interpreter that uses the representation to interpret sentences in the language.
(给定一门语言,定义它的文法的一种表示,并定义一个解释器,该解释器使用该表示来解释语言中的句子。)
通用类图
抽象解释器
定义一个抽象类
终结符表达式类
继承抽象解释器类,通常和抽象解释器一对一,实现与文法中的元素相关联的解释操作
非终结符表达式类
继承抽象解释器类,通常和抽象解释器一对多,文法中的每条规则对应于一个非终结表达式
通用源码
//抽象表达式
template <typename T, typename H>
class Expression {
public:
//每个表达式必须有一个解析任务
virtual T interpreter(H&) = 0;
};
//终结符表达式
template <typename T, typename H>
class TerminalExpression : public Expression<T, H> {
public:
//通常终结符表达式只有一个,但是有多个对象
T interpreter(H& h) {
return null;
}
};
//非终结符表达式
template <typename T, typename H>
class NonerminalExpression : public Expression<T, H> {
//每个非终结符表达式都会对其他表达式产生依赖
public NonerminalExpression (Expression* e) {
}
T interpreter(H& h) {
//进行文法处理
return null;
}
};
优点
解释器是一个简单语法分析工具,扩展性非常好
缺点
导致类膨胀
采用递归调用方法
效率不高
使用场景
重复发生的问题的场景
一个简单语法需要解释的场景
最佳实践
解释器模式因为性能、效率以及维护问题,一般在实际的系统开发中使用得较少。
如果实在需要用到解释器模式时,可以考虑Expression4J、MESP(Math Expression String Parser)、Jep等开源的解析工具包。
示例代码
#include <iostream>
#include <string>
#include <map>
#include <stack>
using namespace std;
class Expression {
public:
virtual int interpreter(map<char, int>&) = 0;
};
class VarExpression : public Expression {
public:
VarExpression(char s): key(s) { }
int interpreter(map<char, int>& mci) override {
return mci[key];
}
private:
char key;
};
class SymbolExpression : public Expression {
public:
SymbolExpression(Expression* l, Expression* r): left(l), right(r) { }
protected:
Expression* left;
Expression* right;
};
class AddExpression : public SymbolExpression {
public:
AddExpression(Expression* l, Expression* r): SymbolExpression(l ,r) { }
int interpreter(map<char, int>& mci) override {
return left->interpreter(mci) + right->interpreter(mci);
}
};
class SubExpression : public SymbolExpression {
public:
SubExpression(Expression* l, Expression* r): SymbolExpression(l ,r) { }
int interpreter(map<char, int>& mci) override {
return left->interpreter(mci) - right->interpreter(mci);
}
};
class Calculator {
public:
Calculator(string s) {
stack<Expression*> se;
Expression* left = nullptr;
Expression* right = nullptr;
for(int i = 0; i < s.size(); ++i) {
if(s[i] == '+') {
left = se.top();se.pop();
right = new VarExpression(s[++i]);
se.push(new AddExpression(left, right));
}else if(s[i] == '-') {
left = se.top();se.pop();
right = new VarExpression(s[++i]);
se.push(new SubExpression(left, right));
}else {
se.push(new VarExpression(s[i]));
}
}
expression = se.top();se.pop();
}
int run(map<char, int> mci) {
return expression->interpreter(mci);
}
private:
Expression* expression;
};
int main() {
string s;
cout << "input Expression: " << endl;
cin >> s;
map<char, int> mci;
for(int i = 0; i < s.size(); ++i) {
if(s[i] != '+' && s[i] != '-') {
cout << "input " << s[i] << " :"<< endl;
int tmp;
cin >> tmp;
mci.insert(make_pair(s[i], tmp));
}
}
Calculator* cal = new Calculator(s);
cout <<"the answer is: " << cal->run(mci) << endl;
return 0;
}