第二十七章-解释器模式
解释器模式(Interpreter): 给定一个语言,定义它的文法中的一种表示,并定义一个解释器,这个解释器使用该表示来解释语言中的句子。
如果一种特定类型的问题发生的频率足够高,那么可能就值得将该问题的各个实例表述为一个简单语言中的句子。这样就可以构建一个解释器,该解释器通过解释这些句子来解决该问题。
解释器模式的好处
通常当有一个语言需要解释执行,并且你可以将该预言中的句子表示为一个抽象语法树时,可使用解释器模式。
用了解释器模式,就意味着可以很容易地改变和扩展文法,因为该模式使用类来表示文法规则,你可以使用继承来改变或扩展该文法。也比较容易实现文法,因为定义抽象语法树中各个节点的类的实现大体类似,这些类都易于直接编写。
但解释器模式也有不足,解释器模式为文法中的每一条规则至少定义了一个类,因此包含许多规则的文法可能难以管理和维护。建议当文法非常复杂时,使用其他的技术如语法分析程序或编译器生成器来处理。
音乐解释器
#include <iostream>
#include<vector>
#include<string>
#include<ctime>
#include<unordered_map>
using namespace std;
class PlayContext
{
private:
string text;
public:
string getText() { return text; }
void setText(string text_t) { text = text_t; }
};
class Expression
{
public:
virtual void Interpret(PlayContext* context)
{
if (context->getText().size() == 0)
return;
else
{
string playKey = context->getText().substr(0, 1);
context->setText(context->getText().substr(2));
int i = 0, j = 0;
string tmp = context->getText();
while (j<tmp.size() && tmp[j] != ' ')
j++;
double playValue = stod(tmp.substr(i, j - i + 1));
if(j < tmp.size())
context->setText(tmp.substr(j + 1));
else
context->setText("");
Excute(playKey[0], playValue);
}
}
virtual void Excute(char key, double value) = 0;
};
class Note :public Expression
{
public:
void Excute(char key, double value)
{
string note;
switch (key)
{
case 'C':
note = "1";
break;
case 'D':
note = "2";
break;
case 'E':
note = "3";
break;
case 'F':
note = "4";
break;
case 'G':
note = "5";
break;
case 'A':
note = "6";
break;
case 'B':
note = "7";
break;
}
cout << note << " ";
}
};
class Scale : public Expression
{
public:
void Excute(char key, double value)
{
string scale;
switch (int(value))
{
case 1:
scale = "低音";
break;
case 2:
scale = "中音";
break;
case 3:
scale = "高音";
break;
}
cout << scale << " ";
}
};
class Speed :public Expression
{
public:
void Excute(char key, double value)
{
string speed;
if (value < 500)
speed = "快速";
else if (value >= 1000)
speed = "慢速";
else
speed = "中速";
cout << speed << " ";
}
};
int main()
{
PlayContext* context = new PlayContext();
cout << "上海滩:" << endl;
context->setText("T 500 O 2 E 0.5 G 0.5 A 3 E 0.5 G 0.5 D 3 E 0.5 G 0.5 A 0.5 O 3 C 1 O 2 A 0.5 G 1 C 0.5 E 0.5 D 3");
Expression* expression = nullptr;
while (context->getText().size())
{
string str = context->getText().substr(0, 1);
switch (str[0])
{
case 'O':
expression = new Scale();
break;
case 'T':
expression = new Speed();
break;
case 'C':
case 'D':
case 'E':
case 'F':
case 'G':
case 'A':
case 'B':
case 'P':
expression = new Note();
break;
}
expression->Interpret(context);
}
system("pause");
return 0;
}