经验首页 前端设计 程序设计 Java相关 移动开发 数据库/运维 软件/图像 大数据/云计算 其他经验
当前位置:技术经验 » Java相关 » 设计模式 » 查看文章
设计模式-行为型-解释器模式
来源:cnblogs  作者:酷学大叔  时间:2019/10/11 10:11:34  对本文有异议

解释器模式(Interpreter):

  从名称上来看看这个模式,个人的最初理解“解释器”和Google的中英翻译功能类似。如果有一天你去国外旅游去了,比如去美国吧,美国人是讲英语的,我们是讲汉语的,如果英语听不懂,讲不好,估计沟通就完蛋了,不能沟通,估计玩的就很难尽兴了,因为有很多景点的解说你可能不明白(没有中文翻译的情况下,一般情况会有的)。所以我们需要一个软件,可以把中英文互译,那彼此就可以更好的理解对方的意思,我感觉翻译软件也可以称得上是解释器,把你不懂的解释成你能理解的。我们写代码,需要编译器把我们写的代码编译成机器可以理解的机器语言,从这方面来讲,C#的编译器也是一种解释器。

解释器模式的角色:

   

  1)抽象解释器(AbstractExpression):定义解释器的接口,约定解释器的解释操作。其中的Interpret接口,正如其名字那样,它是专门用来解释该解释器所要实现的功能。

  2)终结符表达式(TermialExpression):实现了抽象表达式角色所要求的接口,主要是一个interpret()方法;文法中的每一个终结符都有一个具体终结表达式与之相对应。比如有一个简单的公式R=R1+R2,在里面R1和R2就是终结符,对应的解析R1和R2的解释器就是终结符表达式。

  3)非终结符表达式(NonterminalExpression):文法中的每一条规则都需要一个具体的非终结符表达式,非终结符表达式一般是文法中的运算符或者其他关键字,比如公式R=R1+R2中,“+”就是非终结符,解析“+”的解释器就是一个非终结符表达式。

  4)环境角色(Context):这个角色的任务一般是用来存放文法中各个终结符所对应的具体值,比如R=R1+R2,我们给R1赋值100,给R2赋值200。这些信息需要存放到环境角色中,很多情况下我们使用Map来充当环境角色就足够了。

  我们演示一个判断且或的例子。 

  1. 1 public abstract class AbstractExpression
  2. 2 {
  3. 3 public abstract bool Interpret(string context);
  4. 4 }
  5. 5
  6. 6 public class TerminalExpression : AbstractExpression
  7. 7 {
  8. 8 private string data;
  9. 9
  10. 10 public TerminalExpression(string data)
  11. 11 {
  12. 12 this.data = data;
  13. 13 }
  14. 14
  15. 15 public override bool Interpret(string context)
  16. 16 {
  17. 17 return data.Contains(context);
  18. 18 }
  19. 19 }
  20. 20
  21. 21 public class OrExpression : AbstractExpression
  22. 22 {
  23. 23 private AbstractExpression expr1 = null;
  24. 24 private AbstractExpression expr2 = null;
  25. 25
  26. 26 public OrExpression(AbstractExpression expr1, AbstractExpression expr2)
  27. 27 {
  28. 28 this.expr1 = expr1;
  29. 29 this.expr2 = expr2;
  30. 30 }
  31. 31
  32. 32 public override bool Interpret(string context)
  33. 33 {
  34. 34 return expr1.Interpret(context) || expr2.Interpret(context);
  35. 35 }
  36. 36 }
  37. 37
  38. 38 public class AndExpression : AbstractExpression
  39. 39 {
  40. 40 private AbstractExpression expr1 = null;
  41. 41 private AbstractExpression expr2 = null;
  42. 42
  43. 43 public AndExpression(AbstractExpression expr1, AbstractExpression expr2)
  44. 44 {
  45. 45 this.expr1 = expr1;
  46. 46 this.expr2 = expr2;
  47. 47 }
  48. 48
  49. 49 public override bool Interpret(string context)
  50. 50 {
  51. 51 return expr1.Interpret(context) || expr2.Interpret(context);
  52. 52 }
  53. 53 }
  54. 54
  55. 55 public class Program
  56. 56 {
  57. 57 //规则:Robert 和 John 是男性
  58. 58 public static AbstractExpression GetMaleExpression()
  59. 59 {
  60. 60 AbstractExpression robert = new TerminalExpression("Robert");
  61. 61 AbstractExpression john = new TerminalExpression("John");
  62. 62 return new OrExpression(robert, john);
  63. 63 }
  64. 64
  65. 65 //规则:Julie 是一个已婚的女性
  66. 66 public static AbstractExpression GetMarriedWomanExpression()
  67. 67 {
  68. 68 AbstractExpression julie = new TerminalExpression("Julie");
  69. 69 AbstractExpression married = new TerminalExpression("Married");
  70. 70 return new AndExpression(julie, married);
  71. 71 }
  72. 72
  73. 73 public static void Main(string[] args)
  74. 74 {
  75. 75 AbstractExpression isMale = GetMaleExpression();
  76. 76 AbstractExpression isMarriedWoman = GetMarriedWomanExpression();
  77. 77
  78. 78 Console.WriteLine($"John is male? {isMale.Interpret("John")}");
  79. 79 Console.WriteLine($"Julie is a married women? {isMarriedWoman.Interpret("Married Julie")}");
  80. 80 }
  81. 81 }

  这里我们可以得出:解释器模式有很好的扩展模式,或此时我们希望能够找到一位男士已婚,我们只需要再写一个非终结符表达式即可,易于扩展。我们再来看下面这个例子。

  1. 1 // 抽象表达式
  2. 2 public abstract class Expression
  3. 3 {
  4. 4 protected Dictionary<string, int> table = new Dictionary<string, int>(9);
  5. 5
  6. 6 protected Expression()
  7. 7 {
  8. 8 table.Add("", 1);
  9. 9 table.Add("", 2);
  10. 10 table.Add("", 3);
  11. 11 table.Add("", 4);
  12. 12 table.Add("", 5);
  13. 13 table.Add("", 6);
  14. 14 table.Add("", 7);
  15. 15 table.Add("", 8);
  16. 16 table.Add("", 9);
  17. 17 }
  18. 18
  19. 19 public virtual void Interpreter(Context context)
  20. 20 {
  21. 21 if (context.Statement.Length == 0)
  22. 22 {
  23. 23 return;
  24. 24 }
  25. 25
  26. 26 foreach (string key in table.Keys)
  27. 27 {
  28. 28 int value = table[key];
  29. 29
  30. 30 if (context.Statement.EndsWith(key + GetPostFix()))
  31. 31 {
  32. 32 context.Data += value * this.Multiplier();
  33. 33 context.Statement = context.Statement.Substring(0, context.Statement.Length - this.GetLength());
  34. 34 }
  35. 35 if (context.Statement.EndsWith(""))
  36. 36 {
  37. 37 context.Statement = context.Statement.Substring(0, context.Statement.Length - 1);
  38. 38 }
  39. 39 }
  40. 40 }
  41. 41
  42. 42 public abstract string GetPostFix();
  43. 43
  44. 44 public abstract int Multiplier();
  45. 45
  46. 46 //这个可以通用,但是对于个位数字例外,所以用虚方法
  47. 47 public virtual int GetLength()
  48. 48 {
  49. 49 return this.GetPostFix().Length + 1;
  50. 50 }
  51. 51 }
  52. 52
  53. 53 //个位表达式
  54. 54 public sealed class GeExpression : Expression
  55. 55 {
  56. 56 public override string GetPostFix()
  57. 57 {
  58. 58 return "";
  59. 59 }
  60. 60
  61. 61 public override int Multiplier()
  62. 62 {
  63. 63 return 1;
  64. 64 }
  65. 65
  66. 66 public override int GetLength()
  67. 67 {
  68. 68 return 1;
  69. 69 }
  70. 70 }
  71. 71
  72. 72 //十位表达式
  73. 73 public sealed class ShiExpression : Expression
  74. 74 {
  75. 75 public override string GetPostFix()
  76. 76 {
  77. 77 return "";
  78. 78 }
  79. 79
  80. 80 public override int Multiplier()
  81. 81 {
  82. 82 return 10;
  83. 83 }
  84. 84 }
  85. 85
  86. 86 //百位表达式
  87. 87 public sealed class BaiExpression : Expression
  88. 88 {
  89. 89 public override string GetPostFix()
  90. 90 {
  91. 91 return "";
  92. 92 }
  93. 93
  94. 94 public override int Multiplier()
  95. 95 {
  96. 96 return 100;
  97. 97 }
  98. 98 }
  99. 99
  100. 100 //千位表达式
  101. 101 public sealed class QianExpression : Expression
  102. 102 {
  103. 103 public override string GetPostFix()
  104. 104 {
  105. 105 return "";
  106. 106 }
  107. 107
  108. 108 public override int Multiplier()
  109. 109 {
  110. 110 return 1000;
  111. 111 }
  112. 112 }
  113. 113
  114. 114 //万位表达式
  115. 115 public sealed class WanExpression : Expression
  116. 116 {
  117. 117 public override string GetPostFix()
  118. 118 {
  119. 119 return "";
  120. 120 }
  121. 121
  122. 122 public override int Multiplier()
  123. 123 {
  124. 124 return 10000;
  125. 125 }
  126. 126
  127. 127 public override void Interpreter(Context context)
  128. 128 {
  129. 129 if (context.Statement.Length == 0)
  130. 130 {
  131. 131 return;
  132. 132 }
  133. 133
  134. 134 ArrayList tree = new ArrayList();
  135. 135
  136. 136 tree.Add(new GeExpression());
  137. 137 tree.Add(new ShiExpression());
  138. 138 tree.Add(new BaiExpression());
  139. 139 tree.Add(new QianExpression());
  140. 140
  141. 141 foreach (string key in table.Keys)
  142. 142 {
  143. 143 if (context.Statement.EndsWith(GetPostFix()))
  144. 144 {
  145. 145 int temp = context.Data;
  146. 146 context.Data = 0;
  147. 147
  148. 148 context.Statement = context.Statement.Substring(0, context.Statement.Length - this.GetLength());
  149. 149
  150. 150 foreach (Expression exp in tree)
  151. 151 {
  152. 152 exp.Interpreter(context);
  153. 153 }
  154. 154 context.Data = temp + context.Data * this.Multiplier();
  155. 155 }
  156. 156 }
  157. 157 }
  158. 158 }
  159. 159
  160. 160 //亿位表达式
  161. 161 public sealed class YiExpression : Expression
  162. 162 {
  163. 163 public override string GetPostFix()
  164. 164 {
  165. 165 return "亿";
  166. 166 }
  167. 167
  168. 168 public override int Multiplier()
  169. 169 {
  170. 170 return 100000000;
  171. 171 }
  172. 172
  173. 173 public override void Interpreter(Context context)
  174. 174 {
  175. 175 ArrayList tree = new ArrayList();
  176. 176
  177. 177 tree.Add(new GeExpression());
  178. 178 tree.Add(new ShiExpression());
  179. 179 tree.Add(new BaiExpression());
  180. 180 tree.Add(new QianExpression());
  181. 181
  182. 182 foreach (string key in table.Keys)
  183. 183 {
  184. 184 if (context.Statement.EndsWith(GetPostFix()))
  185. 185 {
  186. 186 int temp = context.Data;
  187. 187 context.Data = 0;
  188. 188 context.Statement = context.Statement.Substring(0, context.Statement.Length - this.GetLength());
  189. 189
  190. 190 foreach (Expression exp in tree)
  191. 191 {
  192. 192 exp.Interpreter(context);
  193. 193 }
  194. 194 context.Data = temp + context.Data * this.Multiplier();
  195. 195 }
  196. 196 }
  197. 197 }
  198. 198 }
  199. 199
  200. 200 //环境上下文
  201. 201 public sealed class Context
  202. 202 {
  203. 203 private string _statement;
  204. 204 private int _data;
  205. 205
  206. 206 public Context(string statement)
  207. 207 {
  208. 208 this._statement = statement;
  209. 209 }
  210. 210
  211. 211 public string Statement
  212. 212 {
  213. 213 get { return this._statement; }
  214. 214 set { this._statement = value; }
  215. 215 }
  216. 216
  217. 217 public int Data
  218. 218 {
  219. 219 get { return this._data; }
  220. 220 set { this._data = value; }
  221. 221 }
  222. 222 }
  223. 223
  224. 224 internal class Program
  225. 225 {
  226. 226 private static void Main(string[] args)
  227. 227 {
  228. 228 string roman = "五亿七千三百零二万六千四百五十二";
  229. 229 //分解:((五)亿)((七千)(三百)(零)(二)万)
  230. 230 //((六千)(四百)(五十)(二))
  231. 231
  232. 232 Context context = new Context(roman);
  233. 233 List<Expression> tree = new List<Expression>();
  234. 234 tree.Add(new GeExpression());
  235. 235 tree.Add(new ShiExpression());
  236. 236 tree.Add(new BaiExpression());
  237. 237 tree.Add(new QianExpression());
  238. 238 tree.Add(new WanExpression());
  239. 239 tree.Add(new YiExpression());
  240. 240
  241. 241 foreach (Expression exp in tree)
  242. 242 {
  243. 243 exp.Interpreter(context);
  244. 244 }
  245. 245
  246. 246 Console.Write(context.Data);
  247. 247 }
  248. 248 }

  看完之后是不是想骂一句fuck,我只是想要简单的转换一下,却需要写这么一大坨,显然不符合我们的心意。

解释器模式的优缺点:

  优点:

    1)易于改变和扩展文法。

    2)每一条文法规则都可以表示为一个类,因此可以方便地实现一个简单的语言。

    3)实现文法较为容易。在抽象语法树中每一个表达式节点类的实现方式都是相似的,这些类的代码编写都不会特别复杂,还可以通过一些工具自动生成节点类代码。

    4)增加新的解释表达式较为方便。如果用户需要增加新的解释表达式只需要对应增加一个新的终结符表达式或非终结符表达式类,原有表达式类代码无须修改,符合“开闭原则”。

  缺点:

    1)对于复杂文法难以维护。在解释器模式中,每一条规则至少需要定义一个类,因此如果一个语言包含太多文法规则,类的个数将会急剧增加,导致系统难以管理和维护,此时可以考虑使用语法分析程序等方式来取代解释器模式。

    2)执行效率较低。由于在解释器模式中使用了大量的循环和递归调用,因此在解释较为复杂的句子时其速度很慢,而且代码的调试过程也比较麻烦。

解释器模式的应用场景:

  1)当一个语言需要解释执行,并可以将该语言中的句子表示为一个抽象语法树的时候,可以考虑使用解释器模式(如XML文档解释、正则表达式等领域)。

  2)一些重复出现的问题可以用一种简单的语言来进行表达。

  3)一个语言的文法较为简单.

  4)当执行效率不是关键和主要关心的问题时可考虑解释器模式(注:高效的解释器通常不是通过直接解释抽象语法树来实现的,而是需要将它们转换成其他形式,使用解释器模式的执行效率并不高。)

参考:https://www.cnblogs.com/PatrickLiu/p/8242238.html 

原文链接:http://www.cnblogs.com/az4215/p/11648518.html

 友情链接:直通硅谷  点职佳  北美留学生论坛

本站QQ群:前端 618073944 | Java 606181507 | Python 626812652 | C/C++ 612253063 | 微信 634508462 | 苹果 692586424 | C#/.net 182808419 | PHP 305140648 | 运维 608723728

W3xue 的所有内容仅供测试,对任何法律问题及风险不承担任何责任。通过使用本站内容随之而来的风险与本站无关。
关于我们  |  意见建议  |  捐助我们  |  报错有奖  |  广告合作、友情链接(目前9元/月)请联系QQ:27243702 沸活量
皖ICP备17017327号-2 皖公网安备34020702000426号