解释器模式
理论
解释器模式(interpreter),给定一个语言,定义它的文法的一种表示,并定义一个解释器,这个解释器使用该表示来解释语言中的句子。
解释器模式的应用场景:
当有一个语言需要解释执行,并且可将该语言中的句子表示为一个抽象语法树时,可使用解释器模式。
解释器模式的优点:
1. 可以很容易地改变和扩展文法,因为该模式使用类来表示文法规则,可使用继承来改变和扩展该文法。
2. 也比较容易实现文法,因为定义抽象语法树中各个节点地类地实现大体类似,这些类都易于直接编写。
解释器模式的缺点:
解释器模式为文法中地每一条规则至少定义了一个类,因此包含许多规则地文法可能难以管理和维护。建议当文法非常复杂时,使用其他技术如语法分析程序或编译器生成器来处理。
实例
实现音乐解释器,定义一套规则:
T表示速度,以毫秒为单位;
O 表示音阶, O1 表示低音阶, O2 表示中音阶, O3 表示高音阶;
P 表示休止符;
C D E F G A B 表示 “Do-Re-Mi-Fa-So-La-Ti”;
音符长度1表示一拍,2表示二拍,0.5表示半拍,0.25表示四分之一拍;
所有字母和数字都要用半角空格分开。
UML类图
代码实现
#include <iostream> #include <sstream> #include <vector> using namespace std; //演奏内容类 class PlayContext { public: void SetText(string _text) { text = _text; } string GetText() { return text; } private: string text; }; //抽象表达式类 class Expression { public: virtual void Excute(string key, string value) = 0; void Interpret(PlayContext* context) { if (context->GetText().length() == 0) return; else { vector<string> vs; stringstream ss(context->GetText()); //使用字符串构造一个stringstream //按空格分割字符串 string buf; while (ss >> buf) vs.push_back(buf); //解释前两个字符串 Excute(vs[0], vs[1]); //拼接剩下的字符串 string tmp; vs.erase(vs.begin(), vs.begin() + 2); for (vector<string>::iterator it = vs.begin(); it != vs.end(); it++) { tmp += *it; if (it < vs.end() - 1) tmp += " "; } //更新字符串 context->SetText(tmp); } } }; //音符类 class Note :public Expression { public: void Excute(string key, string value) { string note = " "; switch (key[0]) { 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; default: break; } cout << note << " "; } }; //音阶类 class Scale :public Expression { public: virtual void Excute(string key, string value) { string scale = " "; switch (value[0]) { case'1': scale = "低音"; break; case'2': scale = "中音"; break; case'3': scale = "高音"; break; default: break; } cout << scale << " "; } }; //音速类 class Speed : public Expression { public: void Excute(string key, string value) { int v = stoi(value); if (v < 500) cout << "快速 "; else if (v > 1000) cout << "慢速 "; else cout << "中速 "; } }; int main() { PlayContext context; cout << "上海滩: " << endl; context.SetText("T 600 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"); Expression* expression = NULL; while (context.GetText().length() > 0) { char str = context.GetText()[0]; switch (str) { 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; default: break; } expression->Interpret(&context); delete expression; } cout << endl; return 0; }
运行结果: