Sunny Chen的专栏

欢迎进入Sunny Chen的blog!

陈晴阳ID:acqy
51217次访问,排名2051好友0人,关注者1
陈晴阳,2003年毕业于中南大学铁道学院计算机专业。MCP/MCAD,国家认证高级程序员、系统分析员,中国系统分析员协会顾问团顾问。软件设计与构架、信息系统建设的爱好者。具有三年Microsoft Axapta/Dynamics AX的开发经验。
acqy的文章
原创 25 篇
翻译 0 篇
转载 0 篇
评论 23 篇
acqy的公告

发送邮件


最近评论
czdvcc:wow power leveling
xzy110:中国软件的悲哀!
acqy:void interrupt newint(__ARGU); 这是定义一个中断函数。interrupt是中断函数修饰符,专门用于定义中断函数的。在该修饰符所定义的函数中最好不要使用类似printf这样的函数,因为它会破坏中断运行的环境(例如这类函数中使用了其它未保护中断),编译的时候自然不会出错,但是有可能造成运行的不稳定。具体的内容需要参考Turbo C的帮助文档和《DOS中断大全》一书<……
Editing:请教楼主:
void interrupt 类型函数的参数到底干什么用的?
这类函数的出口参数是怎么设置的?
麻烦楼主解答一下,谢谢!
TIMEREACH:int MyIntArray[100] 的意思就是
int[100] MyIntArray
这样是不是就好理解一点了呢?
文章分类
收藏
    相册
    湘潭大学
    友情链接
    mailbomb的专栏
    存档
    软件项目交易
    订阅我的博客
    XML聚合  FeedSky
    订阅到鲜果
    订阅到Google
    订阅到抓虾
    订阅到BlogLines
    订阅到Yahoo
    订阅到GouGou
    订阅到飞鸽
    订阅到Rojo
    订阅到newsgator
    订阅到netvibes

    原创 C#中使用简单工厂模式实现命令解释器收藏

    新一篇: 面向对象分析与设计和面向对象语言 | 旧一篇: Linux服务器开发初步

     

     

        现假设需要实现一个简单的算术计算解释器,在这个算术计算解释器中,用户通过使用add、subtract、multiply和divide命令分别获得两个无符号整形参数(非负整数)的和、差、积以及商。传统的做法是从标准输入或文件逐条地读入命令,并由专门的语法和语义解析程序对每条命令进行语法和语义分析,然后根据命令的语义对参数进行计算并输出结果。这种方法的优点在于实现思路简单,设计的核心就在于这个专门的语法和语义解析程序,然而这并不是一个好的做法,因为程序的扩充性不强,当我们需要向解释器中添加一个新的命令时,我们需要修改语法语义解析程序。
    在C#中使用简单工厂模式就可以很好地解决这个问题。首先我们回顾一下简单工厂模式。简单工厂模式是一种类的创建型模式,它可以通过向工厂类传递参数来创建所需产品类的实例。在简单工厂模式中,所有的产品类都从同一个接口继承,并实现接口中的方法,工厂类在获得参数后,根据参数的取值来创建不同产品类的实例。下图简要地描述了简单工厂模式的基本结构。


     

    图一 简单工厂模式类示意图

        在上图中,产品类Product1和Product2继承了IProduct接口,产品工厂类ProductFactory的CreateProduct方法用于根据外部传入的参数来生成相应产品类的实例,用户类UserClass通过使用工厂类ProductFactory的CreateProduct方法来获得该实例。
        现在再来讨论算术计算解释器的设计方法。我们可以将解释器所要解释的命令看成是对象,那么解释器执行命令的过程就是创建对象并执行对象中特定操作的过程。通过分析不难发现,对于一个命令而言,最主要的就是能够正确地分析该命令的语法并执行该命令,当然,更多地为用户考虑,我们可以再多定义一个help命令,用于获得其它命令的帮助信息。
        首先我们必须通过分析来得到这样的信息,对于这个算术计算解释器中的命令对象,它们有哪些相同的操作,以便于确定工厂模式的产品接口(即IProduct接口)中应该包括哪些方法的声明。在确定了这个产品接口后,其它的命令类只要继承该产品接口,就可以被工厂类(即ProductFactory类)实例化,进而通过执行实例中的接口方法来达到执行命令的目的。同样,当需要向解释器中添加新的命令时,只需要创建一个新的继承于产品接口的类,并实现产品接口中预先定义的方法即可。
        在解释器产品接口的所有方法中,最为重要的是命令的执行方法,该方法决定了命令的执行逻辑(也就是确定当前命令的输入是什么,将得到什么样的输出),这一点是显而易见的。在上面的分析中我们提到,需要再提供一个help命令,用于显示各命令的帮助信息,因此,解释器中的每条命令还需要有一个GetHelpText方法,用来返回该命令的帮助文本。综上所述,解释器产品接口中至少要有两个方法:Execute方法和GetHelpText方法。在C#中,我们可以使用下面的代码来定义这个产品接口。
    using System;

    namespace SimpleCalc.ICalc
    {
     ///


     /// 算术计算解释器产品接口(IProduct)
     ///
     public interface ICalcCommand
     {
      ///
      /// 命令执行方法
      ///
      /// 命令的参数
      /// 命令执行结果
      int Execute(string[] _parms);
      ///
      /// 用于返回命令的帮助文本信息
      ///
      /// 命令的帮助信息
      string GetHelpText();
     }
    }
        在确定了命令解释器的产品接口后,我们暂不讨论各条命令产品类的具体实现方法,先来看看产品工厂类的实现。对于命令解释器的产品工厂类,它需要从外界获得一个命令名称的参数,用于标识外界需要工厂类实例化哪个产品类。在C#中,可以通过这个参数构造出类的长格式名称,然后使用Reflection技术生成指定类的实例。下面的C#代码实现了命令解释器的产品工厂类。
    using System;
    using System.Reflection;
    using SimpleCalc.ICalc;

    namespace SimpleCalc.Main
    {
     ///


     /// 命令解释器的产品工厂抽象类
     ///
     public abstract class CommandFactory
     {
      public static ICalcCommand GetCommandInstance(string _cmdName)
      {
       try
       {
        string path   = "Commands";
        string className = "SimpleCalc.Commands." + _cmdName.ToUpper();
        return (ICalcCommand) Assembly.Load(path).CreateInstance(className);
       }
       catch
       {
        throw new Exception("Unable to load this command!\n");
       }
      }
     }
    }
        在上面的代码中,CommandFactory类被定义成抽象类,因为该类只有一个GetCommandInstance静态方法,在实际的应用中无需对类进行实例化。
        在定义了工厂类后,命令的执行过程就变得很简单,只需要调用CommandFactory.GetCommandInstance方法获得命令产品类的实例,然后调用该实例的Execute方法就可以了,例如:
    string[] parms = cmd.Split(' ');
    ICalcCommand instance = CommandFactory.GetCommandInstance(parms[0]);
    if (null == instance)
    {
     Console.WriteLine("Unknown command!\n");
     // 。。。
    }
    int result = instance.Execute(parms);
    if (result >= 0)
    {
     Console.WriteLine(string.Format("{0}\n", result));
    }
        现在再来看加法命令(add命令)的实现过程。我们新创建一个名为ADD的类,并使该类继承于ICalcCommand接口,然后分别实现该接口的Execute方法和GetHelpText方法:
    using System;
    using SimpleCalc.ICalc;

    namespace SimpleCalc.Commands
    {
     ///


     /// 加法命令产品类
     ///
     public class ADD : ICalcCommand
     {
      public ADD()
      {
      }
      #region ICalcCommand Members
      public string GetHelpText()
      {
       string txt = "\n";
       txt += "Usage: ADD ";
       return txt;
      }

      public int Execute(string[] _parms)
      {
       uint x, y;
       // 参数格式的判断(ADD命令定义为三个参数,ADD命令本身以及两个非负整数)
       if (_parms.Length != 3)
       {
    throw new Exception(string.Format("This command does not take {0} parameters!", _parms.Length - 1));
       }
       try
       {
        x = Convert.ToUInt32(_parms[1]);
        y = Convert.ToUInt32(_parms[2]);
       }
       catch (System.FormatException ex)
       {
        throw new Exception(ex.Message);
       }
       return (int)(x + y);
      }
      #endregion
     }
    }
        上面的代码中使用了大写的ADD来定义这个类,这是由工厂类中的产品实例化方法(GetCommandInstance方法)所决定的,在该方法中,我们对输入的参数_cmdName执行了ToUpper()操作,以便无论用户输入的命令是“add”还是“Add”,产品实例化方法都能够正确地创建该命令类的实例。与此相似,我们可以向解释器中继续添加subtract、multiply和divide命令。
        最后一个问题,就是如何实现help命令。help命令和add、substract等命令一样,也是被命令解释器所支持的一条命令,因此它也要继承于ICalcCommand接口。在help命令类的Execute方法中,我们需要根据help命令的参数来创建需要获得帮助的命令的实例,并调用实例化对象的GetHelpText方法以显示帮助信息。下面的代码显示了help命令类的Execute方法是如何获得指定命令的帮助信息并将其显示出来的。
    public int Execute(string[] _parms)
    {
     // 参数判断
     if (_parms.Length != 2)
     {
      throw new Exception(string.Format("This command does not take {0} parameters!", _parms.Length - 1));
     }
     try
     {
      // 获得指定的命令名称
      string cmd = _parms[1];
      // 创建该命令的实例
      ICalcCommand instance = CommandFactory.GetCommandInstance(cmd);
      if (null == instance)
      {
       throw new Exception("Unknown command!");
      }
      // 调用实例的GetHelpText方法并将结果显示出来
      Console.WriteLine(instance.GetHelpText());
     }
     catch (Exception ex)
     {
      throw ex;
     }
     return -1;
    }
        下图是已经完成的无符号整数算术计算解释器的运行画面,在命令行中,我们可以方便地使用各种命令来获得需要的计算结果,并可以使用help命令来获得某条命令的帮助信息。

    发表于 @ 2006年07月08日 10:40:00|评论(loading...)|编辑

    新一篇: 面向对象分析与设计和面向对象语言 | 旧一篇: Linux服务器开发初步

    评论:没有评论。

    发表评论  


    当前用户设置只有注册用户才能发表评论。如果你没有登录,请点击登录
    Csdn Blog version 3.1a
    Copyright © acqy