C#面向对象设计模式纵横谈 学习笔记16 Interpreter 解释器模式(行为型模式)

来源:互联网 发布:linux rsync 单向同步 编辑:程序博客网 时间:2024/06/04 22:16

Interpreter模式是一种比较不常用的模式,因为这种模式存在一些弊端,他的使用有很大的条件限制。
Interpreter是一种特殊的设计模式,它建立一个解释器,对于特定的计算机程序设计语言,用来解释预先定义的文法。简单地说,Interpreter模式是一种简单的语法解释器构架。
先借用李建忠老师的代码例子

  1.   public class Program
  2.     {
  3.         static void Main()
  4.         {
  5.             string roman = "二十四万零二";
  6.             
  7.             Context context = new Context(roman);
  8.             ArrayList tree = new ArrayList();
  9.             tree.Add(new GeExpression());
  10.             tree.Add(new ShiExpression());
  11.             tree.Add(new BaiExpression());
  12.             tree.Add(new QianExpression());
  13.             tree.Add(new WanExpression());
  14.             
  15.             foreach(Expression exp in tree)
  16.             {
  17.                 exp.Interpret(context);
  18.             }
  19.             
  20.             Console.WriteLine("{0}={1}", roman, context.Data);
  21.             
  22.             Console.Read();
  23.         }
  24.     }
  25.     
  26.     public class Context
  27.     {
  28.         private string statement;
  29.         private int data;
  30.         
  31.         public Context(string statement)
  32.         {
  33.             this.statement = statement;
  34.         }
  35.         
  36.         
  37.         public string Statement
  38.         {
  39.             get
  40.             {
  41.                 return statement;
  42.             }
  43.             set
  44.             {
  45.                 statement = value;
  46.             }
  47.         }
  48.         
  49.         public int Data
  50.         {
  51.             get
  52.             {
  53.                 return data;
  54.             }
  55.             set
  56.             {
  57.                 data = value;
  58.             }
  59.         }
  60.     }
  61.     
  62.     public abstract class Expression
  63.     {
  64.         protected Dictionary<stringint> table = new Dictionary<string,int>();
  65.         
  66.         public Expression()
  67.         {
  68.             table.Add("一", 1);
  69.             table.Add("二", 2);
  70.             table.Add("三", 3);
  71.             table.Add("四", 4);
  72.             table.Add("五", 5);
  73.             table.Add("六", 6);
  74.             table.Add("七", 7);
  75.             table.Add("八", 8);
  76.             table.Add("九", 9);
  77.         }
  78.         
  79.         public virtual void Interpret(Context context)
  80.         {
  81.             if(context.Statement.Length == 0)
  82.             {
  83.                 return;
  84.             }
  85.             
  86.             
  87.             foreach(string key in table.Keys)
  88.             {
  89.                 int value = table[key];
  90.                 if(context.Statement.EndsWith(key + GetPostfix()))
  91.                 {
  92.                     context.Data += value * Multiplier();
  93.                     context.Statement = context.Statement.Substring(0, context.Statement.Length - GetLength());
  94.                 }
  95.                 
  96.                 if(context.Statement.EndsWith("零"))
  97.                 {
  98.                     context.Statement = context.Statement.Substring(0, context.Statement.Length - 1);
  99.                 }
  100.             }
  101.         }
  102.         
  103.         public abstract string GetPostfix();
  104.         public abstract int Multiplier();
  105.         public virtual int GetLength()
  106.         {
  107.             return this.GetPostfix().Length + 1;
  108.         }
  109.     }
  110.     
  111.     public class GeExpression : Expression
  112.     {
  113.         public override string GetPostfix()
  114.         {
  115.             return string.Empty;
  116.         }
  117.         public override int Multiplier()
  118.         {
  119.             return 1;
  120.         }
  121.         public override int GetLength()
  122.         {
  123.             return 1;
  124.         }
  125.     }
  126.     public class ShiExpression : Expression
  127.     {
  128.         public override string GetPostfix()
  129.         {
  130.             return "十";
  131.         }
  132.         
  133.         public override int Multiplier()
  134.         {
  135.             return 10;
  136.         }
  137.     }
  138.     public class BaiExpression : Expression
  139.     {
  140.         public override string GetPostfix()
  141.         {
  142.             return "百";
  143.         }
  144.         public override int Multiplier()
  145.         {
  146.             return 100;
  147.         }
  148.     }
  149.     public class QianExpression : Expression
  150.     {
  151.         public override string GetPostfix()
  152.         {
  153.             return "千";
  154.         }
  155.         public override int Multiplier()
  156.         {
  157.             return 1000;
  158.         }
  159.     }
  160.     public class WanExpression : Expression
  161.     {
  162.         public override string GetPostfix()
  163.         {
  164.             return "万";
  165.         }
  166.         public override int Multiplier()
  167.         {
  168.             return 10000;
  169.         }
  170.         public override void Interpret(Context context)
  171.         {
  172.             if(context.Statement.Length == 0)
  173.             {
  174.                 return;
  175.             }
  176.             
  177.             ArrayList tree = new ArrayList();
  178.             tree.Add(new GeExpression());
  179.             tree.Add(new ShiExpression());
  180.             tree.Add(new BaiExpression());
  181.             tree.Add(new QianExpression());
  182.             
  183.             foreach(string key in table.Keys)
  184.             {
  185.                 if(context.Statement.EndsWith(this.GetPostfix()))
  186.                 {
  187.                     int temp = context.Data;
  188.                     context.Data = 0;
  189.                     context.Statement = context.Statement.Substring(0, context.Statement.Length - 1);
  190.                     
  191.                     foreach(Expression exp in tree)
  192.                     {
  193.                         exp.Interpret(context);
  194.                     }
  195.                     
  196.                     context.Data = temp + this.Multiplier() * context.Data;
  197.                 }
  198.             }
  199.         }
  200.     }
  201. 分析一下代码。
  202. 这段代码是将中文的数字转换为阿拉伯数字,如果按照面向过程的算法肯定是来截取字符串进行判断然后组合成正确的数字。在这段代码中则利用了interpreter模式将位数进行表达式的封装。
  203. 首先看抽象Expression类,首先他封装了一个字典类,这个字典保存了中文的1-9的字符及其对应的阿拉伯数字。Interpret方法,在便利字典中的每个中文数字,并且判断截取中文数字加其后缀是否是结尾,如果为真那么将对应的值乘以对应的位数,对应的位数是一个纯虚函数Multiplier,由派生类自己实现。在取得了对应的Expression的值后需要将中文数字语句中对应的字符串去掉,即GetLength函数,取得对应的位数符合加1。这是一个虚函数,可以由派生类重写。注意GeExpression就重写了此虚函数,因为个位数的长度是1,而不是位数符加1。
  204. 注意下面这段代码
    1.   if(context.Statement.EndsWith("零"))
    2.                 {
    3.                     context.Statement = context.Statement.Substring(0, context.Statement.Length - 1);
    4.                 }

    这是处理三万零五十类似中间有零来分割的情况,将零去掉。

    在WanExpression中,我们重写了Interpret函数,这是由于万位数可以由千位一下的数字来描述,如三千二百万。重写Interpret函数的算法如下,先将千以下的表达式(包括千)加入一个ArrayList保存起来,然后遍历数字表,如果当前的表达式已经截取到万,那么先将已取得的数值用中间临时变量保存起来,将当前表达式的数字值置为0。然后将万以后的文字截取。在依次用ArrayList里面的千、百、十、个的Expression进行解释,最后取得的数值乘以万对应的位数加上临时变量。这里的算法不用担心亿的情况,因为没有亿的运算符表达式,算到亿的时候,解释器已经算完描述万的数值

在看Main函数的调用,在Main函数里使用ArrayList保存了个十百千万的表达式,依次用这些表达式来解析上下文。注意,解析的顺序是个十百千万的顺序。

解释器模式是用来解释语言的文法的。但是它的适用范围其实很有限:
1.简单文法:对于复杂的文法来说,解释器模式会让类的层次复杂的难以管理,如果个十百千万类似位数符很多,那么派生类的体系将相当庞大。所以此模式适用于文法比较简单的
2.效率无关:追求效率的语法解释通常使用状态机解决。

原创粉丝点击