定义:
给定一个语言,定义它的文法表示,并定义一个解释器,这个解释器使用该标识来解释语言中的句子。
何时使用:
如果一种特定类型的问题发生的频率足够高,那么可能就值得将该问题的各个实例表述为一个简单语言中的句子。这样就可以构建一个解释器,该解释器通过解释这些句子来解决该问题。
如何解决:构建语法树,定义终结符与非终结符。
关键代码:构件环境类,包含解释器之外的一些全局信息,一般是 HashMap。
应用实例:编译器、运算表达式计算。
优点: 1、可扩展性比较好,灵活。 2、增加了新的解释表达式的方式。 3、易于实现简单文法。
缺点: 1、可利用场景比较少。 2、对于复杂的文法比较难维护。 3、解释器模式会引起类膨胀。 4、解释器模式采用递归调用方法。
使用场景: 1、可以将一个需要解释执行的语言中的句子表示为一个抽象语法树。 2、一些重复出现的问题可以用一种简单的语言来进行表达。 3、一个简单语法需要解释的场景。
UML图:
角色分析:
①AbstractExpression:定义解释器的接口,约定解释器的解释操作。其中的Interpret接口,正如其名字那样,它是专门用来解释该解释器所要实现的功能。(如加法解释器中的Interpret接口就是完成两个操作数的相加功能)。
②TerminalExpression:终结符解释器,用来实现语法规则中和终结符相关的操作,不再包含其他的解释器,如果用组合模式来构建抽象语法树的话,就相当于组合模式中的叶子对象,可以有多种终结符解释器。
③NonterminalExpression:非终结符解释器,用来实现语法规则中非终结符相关的操作,通常一个解释器对应一个语法规则,可以包含其他解释器,如果用组合模式构建抽象语法树的话,就相当于组合模式中的组合对象。可以有多种非终结符解释器。
④Context:上下文,通常包含各个解释器需要的数据或是公共的功能。这个Context在解释器模式中起着非常重要的作用。一般用来传递被所有解释器共享的数据,后面的解释器可以从这里获取这些值。
⑤Client:客户端,指的是使用解释器的客户端,通常在这里将按照语言的语法做的表达式转换成使用解释器对象描述的抽象语法树,然后调用解释操作。
点击打开链接//行为型模式:解释器模式
//场景:中文数字转阿拉伯数字
/*
1、使用Interpreter模式来将中文数字转换为数学数字的好处是可以应对中文数字的变化,
虽然可以用一很好的算法将中文转化为数字,解释器的扩展性能比较好,如果出现亿、兆的情况,
可以写出两个类(YiExpression、ZhaoExpression)来继承Expression类,而其他地方的代码都不变化。
2、思路:用单位用分解出不同的解释器.其中个位、十位、百位和千位是终结符解释器,万位是非结终符
解释器,因为万以上的单位可以形成如果九百零一万之类的数字,需要进一进拆分成由结终符
构成的解释器来完成任务。
3、转化:将中文数字串由低位向高位方向不断转化
*/
#include <iostream>
#include <string>
#include <map>
#include <stack>
#include <list>
using namespace std;
//字符串上下文信息:保存没有处理的字符串信息
class Context
{
private:
string statement;
int data;
public:
Context(string _statement):statement(_statement),data(0){}
string& getStatement()
{
return statement;
}
void setStatement(string _statement)
{
statement = _statement;
}
int getData()
{
return data;
}
void setData(int _data)
{
data = _data;
}
};
//抽象类:解释器
class Expression
{
protected:
//数据字典:保存中文数字一到九
static map<string, int> table;//静态数据成员
//辅助函数,用来判判断src字符串是否以tail串结尾
bool stringEndsWith(const string& src, const string& tail)
{
if(src.size() < tail.size())
return false;
string tmp = src.substr(src.size() - tail.size(), tail.size());
return (0==tmp.compare(0,tail.size(),tail));
}
public:
//虚方法:中文数字到数字的转换
virtual void interpret(Context& context)
{
if(context.getStatement().length() == 0)
return;
map<string, int>::iterator iter = table.begin();
while (iter != table.end())
{
string& statement = context.getStatement();
string tail = iter->first + getPostfix();
//从低位往高位分析(如九千三百零五,从右向左分析)
if(stringEndsWith(statement,tail))
{
context.setData(context.getData() + iter->second * multiplier());
//注意,string是ASCII编码,每个中文字符的长度为2
context.setStatement(statement.substr(0, statement.length()-2 - getPostfix().length()));
}
if(stringEndsWith(statement,"零"))
{
//”零“则直接跳过
context.setStatement(statement.substr(0, statement.length()-2));
}
++iter;
}
}
//表达式的后缀是以什么表示的(十、百...)
virtual string getPostfix() = 0;
//表达式的数量级
virtual int multiplier() = 0;
virtual ~Expression(){};
};
//映射表,保存中文数字与罗马数字的映射
static map<string, int>::value_type init_table[] =
{
map<string, int>::value_type("一",1),
map<string, int>::value_type("二",2),
map<string, int>::value_type("三",3),
map<string, int>::value_type("四",4),
map<string, int>::value_type("五",5),
map<string, int>::value_type("六",6),
map<string, int>::value_type("七",7),
map<string, int>::value_type("八",8),
map<string, int>::value_type("九",9)
};
map<string,int> Expression::table(init_table,init_table + 9);
//个位数解释器(终结符表达式)
class GeExpression : public Expression
{
public:
string getPostfix()
{
return "";
}
int multiplier()
{
return 1;
}
};
//十位数解释器(终结符表达式)
class ShiExpression : public Expression
{
public:
string getPostfix()
{
return "十";
}
int multiplier()
{
return 10;
}
};
//百位数解释器(终结符表达式)
class BaiExpression : public Expression
{
public:
string getPostfix()
{
return "百";
}
int multiplier()
{
return 100;
}
};
//千位数解释器(终结符表达式)
class QianExpression : public Expression
{
public:
string getPostfix()
{
return "千";
}
int multiplier()
{
return 1000;
}
};
//万位数解释器(非终结符表达式)
class WanExpression : public Expression
{
public:
string getPostfix()
{
return "万";
}
int multiplier()
{
return 10000;
}
void interpret(Context& context)
{
if(context.getStatement().length() == 0)
return ;
if (stringEndsWith(context.getStatement(),getPostfix()))
{
list<Expression*> exps;
exps.clear();
exps.push_back(new GeExpression());
exps.push_back(new ShiExpression());
exps.push_back(new BaiExpression());
exps.push_back(new QianExpression());
int temp = context.getData();
string& sm = context.getStatement();
context.setData(0);
//string类中每个中文长度为2.
context.setStatement(sm.substr(0, sm.length()-2));
list<Expression*>::iterator iter = exps.begin();
while (iter != exps.end())
{
(*iter)->interpret(context);
++iter;
}
context.setData(temp + multiplier()* context.getData());
iter = exps.begin();
while (iter != exps.end())
{
delete (*iter);
++iter;
}
exps.clear();
}
}
};
//转换器
class Convertor
{
private:
Context context;
string chineseNum;
int result;
list<Expression*> exps;
void reset()
{
context.setStatement(chineseNum);
context.setData(0);
list<Expression*>::iterator iter = exps.begin();
while (iter != exps.end())
{
delete (*iter);
++iter;
}
exps.clear();
}
public:
Convertor(const string chineseNum):context(chineseNum)
{
this ->chineseNum = chineseNum;
result = 0;
}
void convert()
{
reset();
exps.push_back(new GeExpression());
exps.push_back(new ShiExpression());
exps.push_back(new BaiExpression());
exps.push_back(new QianExpression());
exps.push_back(new WanExpression());
list<Expression*>::iterator iter = exps.begin();
while (iter != exps.end())
{
(*iter)->interpret(context);
++iter;
}
result = context.getData();
}
int getRoman()
{
return result;
}
void setChineseNum(const string& chineseNum)
{
this ->chineseNum = chineseNum;
}
~Convertor()
{
reset();
}
};
int main()
{
string chineseNum = "四百九十六万二千三百一十五";
Convertor conv(chineseNum);
conv.convert();
cout << chineseNum << " -> " << conv.getRoman() << endl;
chineseNum = "九千零五万六千零七十二";
conv.setChineseNum(chineseNum);
conv.convert();
cout << chineseNum << " -> " << conv.getRoman() << endl;
return 0;
}
/*输出结果:
四百九十六万二千三百一十五 -> 4962315
九千零五万六千零七十二 -> 90056072
*/