解释器模式(Interpreter Pattern)

简介

解释器模式:给定一个语言,定义它的语法的一种表示,并定义一个解释器,这个解释器使用该表示来解释语言中的句子。

解释器模式需要解决的是,如果一种特定类型的问题发生的频率足够高,那么可能就值得将该问题的各个实例表述为一个简单语言中的句子。这样就可以构建一个解释器,该解释器通过解释这些句子来解决该问题。

比如说,我们常常会在字符串中搜索匹配字符或判断一个字符串是否符合我们规定的格式,此时一般我们会用正则表达式匹配。解释器为正则表达式定义了一个文法,如何表示一个特定的正则表达式,以及如何解释这个正则表达式。

当有一个语言需要解释执行,并且你可以将该语言中的句子表示为一个抽象语法树时,可以使用解释器模式。

用了解释器模式,就意味着可以很容易地改变和扩展文法,因为该模式使用类来表示文法规则,你可以使用继承来改变或者扩展该文法。也比较容易实现文法,因为定义抽象语法树中各个节点的类的实现大体类似,这些类都易于直接编写。

解释器模式也有不足的,解释器模式为文法中的每一条规则至少定义了一个类,因此包含了许多规则的文法可能难以管理和维护。建议当文法非常复杂时,使用其它的技术如语法分析程序或编译器生成器来处理。

实例

音乐解释器

演奏内容类(context)

  1. //演奏内容
  2. class PlayContext
  3. {
  4. //演奏文本
  5. private string text;
  6. public string PlayText
  7. {
  8. get {return text;}
  9. set {text = value;}
  10. }
  11. }

表达式类(AbstractExpression)

  1. abstract class Expression
  2. {
  3. //解释器
  4. public void Interpret(PlayContext context)
  5. {
  6. if (context.PlayText.Length == 0)
  7. {
  8. return;
  9. }
  10. else
  11. {
  12. //此方法用于将当前演奏文本第一条命令获得命令字母和其参数值。例如"O 3 E 0.5 G 0.5 A 3"则playKey为O而playValue为3
  13. string playKey = context.Playtext.subText.subString(0,1);
  14. context.PlayText = context. PlayText.subString(2);
  15. doublePlayValue = Convert.ToDouble(context.PlayText.SubString(0, context.PlayText.IndexOf("")));
  16. context.PlayText = context.PlayText.substring(context.PlayText.IndexOf("") + 1);
  17. Excute(playKey, playValue);
  18. }
  19. }
  20. //执行
  21. public abstract void Excute(string key, doubel value);
  22. }

音符类(TerminalExpression)

  1. class Note: Expression
  2. {
  3. public override void Excute(string key, double value)
  4. {
  5. string note ="";
  6. switch (key)
  7. {
  8. case: "C":
  9. note = "1";
  10. break;
  11. case: "D":
  12. note = "2";
  13. break;
  14. case: "E":
  15. note = "3";
  16. break;
  17. case: "F":
  18. note = "4";
  19. break;
  20. case: "G":
  21. note = "5";
  22. break;
  23. case: "A":
  24. note = "6";
  25. break;
  26. case: "B":
  27. note = "7";
  28. break;
  29. }
  30. Console.Write("{0}", note);
  31. }
  32. }

音符类(TerminalExpression)

  1. class Scale: Expression
  2. {
  3. public override void Excute(string key, double value)
  4. {
  5. string scale = "";
  6. switch (Convert.ToInt32(value))
  7. {
  8. case 1:
  9. scale = "低音";
  10. break;
  11. case 2:
  12. scale = "中音";
  13. break;
  14. case 3:
  15. scale = "高音";
  16. break;
  17. }
  18. Console.Write("{0}",scale);
  19. }
  20. }

客户端代码

  1. static void Main(string[] args)
  2. {
  3. PlayContext context = new PlayContext();
  4. //音乐-上海滩
  5. Console.WriteLine("上海滩:");
  6. context.PlayText = "O 2 E 0.5 G 0.5 A 3 E 0.5 G 0.5 D 3 E 0.5";
  7. Expression expression = null;
  8. try
  9. {
  10. while (context.PlayText.Length > 0)
  11. {
  12. string str = context.PlayText.Substring(0.1);
  13. switch (str)
  14. {
  15. case "O":
  16. expression = new Scale();
  17. break;
  18. case "C":
  19. case "D":
  20. case "E":
  21. case "F":
  22. case "G":
  23. case "A":
  24. case "A":
  25. case "B":
  26. case "P":
  27. expression = new Note();
  28. break;
  29. }
  30. expression.Interpret(context);
  31. }
  32. }
  33. catch (Exception ex)
  34. {
  35. Console.WriteLine(ex.Message);
  36. }
  37. Console.Read();
  38. }

比如说 我现在要增加一个文法,就是演奏速度。

音速类

  1. class Speed :Expression
  2. {
  3. public override void Excute(string key, double value)
  4. {
  5. string speed;
  6. if (value < 500) {
  7. speed = "快速";
  8. } else if (value >= 1000)
  9. {
  10. speed = "慢速";
  11. } else {
  12. speed = "快速";
  13. }
  14. Console.Write("{0}",speed);
  15. }
  16. }

客户端代码(局部)

  1. context.PlayText = "T 500 O 2 E 0.5 G 0.5 A 3 E 0.5 G 0.5 D 3 E 0.5";
  2. Expression expression = null;
  3. try
  4. {
  5. while (context.PlayText.Length > 0)
  6. {
  7. string str = context.PlayText.Substring(0.1);
  8. switch (str)
  9. {
  10. case "O":
  11. expression = new Scale();
  12. break;
  13. case "T":
  14. expression = new Speed();
  15. break;
  16. case "C":
  17. case "D":
  18. case "E":
  19. case "F":
  20. case "G":
  21. case "A":
  22. case "A":
  23. case "B":
  24. case "P":
  25. expression = new Note();
  26. break;
  27. }
  28. expression.Interpret(context);
  29. }
  30. }
  31. catch (Exception ex)
  32. {
  33. Console.WriteLine(ex.Message);
  34. }
  35. Console.Read();
  36. }