设计模式—命令、职责链及解释器模式

来源:互联网 发布:算法导论中文版pdf下载 编辑:程序博客网 时间:2024/06/05 09:20

  Ø  命令模式

    烧烤店与烧烤摊碰撞出的命令模式:

    烧烤摊体现的是客户和老板直接接触的,用程序术语说就是行为请求者(客户)和行为实现者(烧烤摊老板)的关系是紧耦合的。

    怎么说呢?顾客与老板的直接对话使得钱付没付,或者有的东西没了,或者买多了想减少等等视为撤销和重 做,很显然,客户与老板的紧密接触使得撤销重做等要求不易实现,这样强耦合性使得生意场面容易混乱。

    这时烧烤店便可以避免这些问题,借助于第三方来传达一方的请求,任何的撤销与重做都可以通过第三方,也就是我们说的服务员来实现。这样使得老板与客户的耦合性降低,这样方便对于生意的顺利进行。

    那么什么是命令模式呢?

    命令模式,将一个请求封装为一个对象,从而使你可用不同的请求对客户进行参数化;对请求排队或记录请求日志,以及支持可撤销的操作。

    命令模式实质就是将行为请求者和行为实现者解耦,将一组行为抽象为对象,实现二者之间的松耦合。

 

    具体的流程:Receiver负责具体的行为即烤鸡翅和烤羊肉;一个命令接口,烤鸡翅或者烤羊肉实现这个接口,也就是具体的行为;Invoker负责传达顾客的请求,把所有顾客的请求集合起来,通知给receiver的具体行为;顾客希望receiver能够烤出自己想要的烧烤。

     主要看看客户端的代码:

     static void Main(string[] args)

        {            //开店前准备            Barbecuer boy = new Barbecuer();            Command  bakeMuttonCommand1=new BakeMuttonCommand (boy);            Command bakeMuttonCommand2 = new BakeMuttonCommand(boy);            Command bakeChickenWingCommand1 = new BakeChickenWingCommand(boy);            Waiter girl = new Waiter();            //开门营业            girl.SetOrder(bakeMuttonCommand1);            girl.SetOrder(bakeMuttonCommand2);            girl.SetOrder(bakeChickenWingCommand1);            //点菜完毕,通知厨房            girl.Notify();            Console.Read();        }

  Ø  职责链模式

    职责链模式(Chainof Responsibility)使多个对象都有机会处理请求,从而避免请求的发送者和接受者之间的耦合关系。将这个对象连成一条链,并沿着这条链传递该请求,直到有一个对象处理它为止。

    比如小菜请求加薪,上报给了自己部门的经理,可能自己部门的经理无权处理这件事,那么便会把这个请求上交给自己的上一级,可能自己的上一级也无法处理这个请求,可以继续上交给上上一级,但是这个过程小菜是可以不必知道,他需要知道的就是最后的结果,这样做的降低了接受者和请求者的耦合性,便于传递。

    
    主要看看客户端代码:

static void Main(string[] args)        {            CommonManager jinli = new CommonManager("金利");            Majordomo zongjian = new Majordomo("宗剑");            GenenralManager zhongjingli = new GenenralManager("钟精励");            jinli.SetSuperior(zongjian);     //设置上级,完全可以根据实际需求来更改设置            zongjian.SetSuperior(zhongjingli);            Request request = new Request();            request.RequestType = "请假";            request.RequestContent = "小菜请假";            request.Number =1;            jinli.RequestApplications (request );            Request request2 = new Request();            request2.RequestType = "请假";            request2.RequestContent = "小菜请假";            request2.Number = 4;            jinli.RequestApplications(request2);            Request request3 = new Request();            request3.RequestType = "加薪";            request3.RequestContent = "小菜请求加薪";            request3.Number = 500;            jinli.RequestApplications(request3);       //客户端的申请都是由“经理”发出的,但是具体谁来决策由具体类处理,客户端不知道            Request request4 = new Request();            request4.RequestType = "加薪";            request4.RequestContent = "小菜请求加薪";            request4.Number = 1000;            jinli.RequestApplications(request4);            Console.Read();        }

  Ø  解释器模式

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

    这样来说吧,比如拿计算器来说吧,计算器简而言之是一个公式的集合,里面有两种元素:运算元素和运算符号。运算元素就是指a、b、c等符号,需要具体赋值的对象,也叫做终结符号,为什么叫终结符号呢?因为这些元素除了需要赋值外,不需要做任何处理,所有运算元素都对应一个具体的业务参数,这是语法中最小的单元逻辑,不可再拆分;运算符号就是加减符号,需要我们编写算法进行处理,每个运算符号都要对应处理单元,否则公式无法运行,运算符号也叫做非终结符号。

    运算元素和运算符号有个共同点,那就是需要被破析,不同点是所有的运算元素具有相同的功能,可以用一个类表示,而运算符号则是需要分别进行解释,加法需要加法解析器,减法也需要减法解析器。

    比如在简单工厂里,我们可以把要进行运算的两个数放在一个类中进行声明,但是不能把加减乘除放在一个类中声明,因为它们属于不同的运算,故而不能用相同的类表示。

    其中涉及到一个substring的方法:

    public String substring(int beginIndex, int endIndex) 返回一个新字符串,它是此字符串的一个子字符串。

    该子字符串从指定的beginIndex处开始,一直到索引endIndex - 1处的字符。因此,该子字符串的长度为endIndex-beginIndex。

  参数: beginIndex- 开始处的索引(包括)。 

         endIndex - 结束处的索引(不包括)。  

  返回:   指定的子字符串。 

  抛出: IndexOutOfBoundsException - 如果 beginIndex为负,或 endIndex 大 于此 String 对象的长度,或 beginIndex 大于 endIndex。

    程序代码;

using System;using System.Collections.Generic;using System.Linq;using System.Text;namespace ConsoleApplication12{    class PlayContext    {        private string text;  //演奏文本        public string PlayText        {            get { return text ;}            set { text  = value; }        }    }    abstract class Expression    {        //解释器        public void Interpret(PlayContext context)        {            if (context.PlayText.Length == 0)            {                return;            }            else            {                string playKey = context.PlayText.Substring(0, 1);                context.PlayText = context.PlayText.Substring(2);                double playValue = Convert.ToDouble(context.PlayText.Substring(0, context.PlayText.IndexOf(" "))); //引号中的空格很重要                context.PlayText = context.PlayText.Substring(context.PlayText.IndexOf(" ") + 1); //引号中的空格很重要                Excute(playKey, playValue);            }        }        public abstract void Excute(string key, double value);    }    class Note : Expression    {        public override void Excute(string key, double value)        {           string note = "";           switch (key)           {               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 "H":                   note = "6";                   break;               case "I":                   note = "7";                   break;           }           Console.Write("{0}",note);        }    }    class Scale : Expression    {        public override void  Excute(string key, double value)        {        string scale="";            switch (Convert .ToInt32 (value ))            {                case 1:                    scale="低音";                    break ;                case 2:                    scale="中音";                    break ;                case 3:                    scale="高音";                    break ;            }            Console.Write ("{0}",scale );         }        }}

    客户端

 static void Main(string[] args)        {            PlayContext context = new PlayContext();            Console.WriteLine("上海滩:");            context .PlayText ="O 2 E 0.5 G 0.5 A 3 E 0.5 G 0.5 D 3";            Expression expression = null;            try            {                while (context.PlayText.Length > 0)                {                    string str = context.PlayText.Substring(0,1);                    switch (str)                    {                        case "O":                            expression = new Scale();                            break;                        case "C":                        case "D":                        case "E":                        case "F":                        case "G":                        case "A":                        case "B":                        case "P":                            expression = new Note();                            break;                    }                    expression.Interpret(context);                }            }            catch (Exception ex)            {                Console.WriteLine(ex.Message);            }            Console.Read();        }

  Ø  区别于联系

    命令模式传达的是顾客的请求,职责链传达的是员工的请求,而解释器向人们解释某种文法,实际上也是在满足人们的某种请求。他们共同的特点是借助于第三方,来满足自己与直接接受者的联系,也就是降低了请求者与接受者之间的耦合性,使得它们之间的直接相互关系不强烈,这样使得程序更易灵活实现。

    不同之处就是它们各自的适用之处。

    命令模式

    优点:可以较容易地设计一个命令队列

          在需要的情况下,可以较容易地将命令记入日志。

          允许接受请求的一方决定是否要否定请求

          可以较容易地实现对请求的撤销和重做

          加进新的具体命令类不影响其他的类,易于加进新命令

          关键之处:命令模式把请求一个操作的对象与知道怎么执行一个操作的对象分隔开。

    职责链模式

    优点:接受者和发送者都没有对方的明确信息,且链中的对象自己也不知道链的结构。

          职责链可以简化对象的相互连接,且只需保持一个指向其后继者的引用,不需保持它所有候选接受者的引用。

          随时随地增加或者修改处理一个请求的结构,增加了给对象指派职责的灵活性。

           关键之处:当客户提交一个请求时,请求是沿着链传递直至有一个具体的操作者对象负责处理它。

    解释器模式

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

          该模式使用类来表示文法规则,可以使用继承来扩展或改变文法。

          该模式定义抽象语法树中各个节点的类的实现大体相似,且这些类易于直接编写,所以文法的实现比较容易。

           解释器模式就是把某句话转变成实际的命令程序执行,由于其通过继承抽象表达式及依赖倒转原则,使得对于文法的扩展和维护都带来了方便。

    不足:解释器为文法中的每一条规则至少定义了一个类,那么多条规则可能包含多个类,这样使得维护和管理成了难点。


0 0
原创粉丝点击