模式七:命令模式

    7.1命令模式定义

   命令模式将请求(命令)封闭成对象,以便使用不同的请求、队列或者日志来参数化其它对象(命令的发布者)。命令模式也支持可撤消的操作。

 

      7.2命令模式UML类图

 

 

 

 

7.3应用场景 

 命令在生活中随处可见,例如我们开灯这个动作,人是发出命令的对象(对应Invoker),开是命令(对应Command),灯是命令的接收者(执行命令的具体对象,对应Receiver)。当我们需要将命令的请求者和执行者之间解耦(即请求者不依赖于具体的执行者,而依赖于执行者动作的抽象。这个原则已经在多个设计模式中不知道出现多少遍了,呵呵。),我们就可以使用命令模式。命令模式还可应用于队列请求,这里队列中的元素即为一条命令,由于每个命令都实现了Command接口,所以Invoker只需调用队列中命令的Execute()方法就可以执行命令了,而不需要知道Execute()具体执行的是什么命令。当我们把一系列命令打包成一个队列,则这个命令队列可以在不同的Invoker之间传递,这样就实现了“命令集”在不同的Invoker之间复用。同样,命令模式还可以应用于日志和事务系统。例如:我们将曾经执行的命令作为日志存储起来,这样如果我们执行命令的过程中,因为某些原因系统死机而导致命令执行的结果未保存,这时我们可以根据日志上的命令轨迹来重新执行。

 

7.4命令模式分析与实现(c#描述)

//命令接口

    public interface ICommand {

     

       void Execute();

       void Undo();

  

   }

 

    //命令执行者:灯

    public class Light {

 

        public void LightOn()

        {

            System.Console.WriteLine("现在开灯了。");       

        }

 

        public void LightOff()

        {

            System.Console.WriteLine("现在关灯了。");

        }

   

    }

 

    //具体命令:开灯

    public class LightOnCommand : ICommand

    {

        private Light iobj_Light;

        public LightOnCommand(Light aobj_Light)

        {

            this.iobj_Light = aobj_Light;

        }

 

        public void Execute()

        {

            this.iobj_Light.LightOn();

        }

 

        public void Undo()

        {

            this.iobj_Light.LightOff();       

        }   

    }

 

 

    //具体命令:关灯

    public class LightOffCommand : ICommand

    {

        private Light iobj_Light;

        public LightOffCommand(Light aobj_Light)

        {

            this.iobj_Light = aobj_Light;

        }

 

        public void Execute()

        {

            this.iobj_Light.LightOff();

        }

 

        public void Undo()

        {

            this.iobj_Light.LightOn();

        }

    }

 

    //命令发布者1-每次只能执行单一命令

    public class Invoker1

    {

        private ICommand iobj_Command;//Invoker并不知道是什么执行者被传了进来。

 

        public void SetCommand(ICommand aobj_Command)

        {

            this.iobj_Command = aobj_Command;

        }

 

        public void Execute()

        {

            if (this.iobj_Command != null) this.iobj_Command.Execute();

        }

 

        public void Undo()

        {

            if (this.iobj_Command != null) this.iobj_Command.Undo();

        }

    }

 

    //命令发布者1-每次执行一组命令

    public class Invoker2

    {

        private ICommand[] iobj_Commands;//Invoker并不知道是什么执行者被传了进来。

 

 

        public void SetCommands(ICommand[] aobj_Commands)

        {

            this.iobj_Commands = aobj_Commands;

        }

 

        public void Execute()//执行一组命令

        {

            if (this.iobj_Commands != null)

            {

                for (int lint_LoopCount = 0; lint_LoopCount < this.iobj_Commands.Length; lint_LoopCount++)

                {

                    this.iobj_Commands[lint_LoopCount].Execute();

                }

            }

        }

 

        public void Undo()//撤消一组命令

        {

            if (this.iobj_Commands != null)

            {

                for (int lint_LoopCount = 0; lint_LoopCount < this.iobj_Commands.Length; lint_LoopCount++)

                {

                    this.iobj_Commands[lint_LoopCount].Undo();

                }

            }

        }

    }

 

 

 

    //调用类

    public class Command_Test

    {

        public static void Do1()//执行单一命令

        {

            Invoker1 lobj_Invoker = new Invoker1();//New一个命令发布者对象

            Light lobj_Light=new Light();//New一个电灯对象

 

            LightOnCommand lobj_LightOnCommand = new LightOnCommand(lobj_Light);//New一个命令对象:开灯

            lobj_Invoker.SetCommand(lobj_LightOnCommand);//用开灯命令参数化Invoker

            lobj_Invoker.Execute();//执行命令

            lobj_Invoker.Undo();//撤消命令

 

            LightOffCommand lobj_LightOffCommand = new LightOffCommand(lobj_Light);//New一个命令对象:关灯

            lobj_Invoker.SetCommand(lobj_LightOffCommand);//用关灯命令参数化Invoker

            lobj_Invoker.Execute();//执行命令

            lobj_Invoker.Undo();//撤消命令

 

            //总结:命令的发布者Invoker只依赖于命令对象的抽象ICommand,而与具体的命令执行者完全没有关系,这样就实现了命令的请求者和执行者之间的解耦。

        }

 

        public static void Do2()//执行一组命令

        {

            Invoker2 lobj_Invoker = new Invoker2();//New一个命令发布者对象

            Light lobj_Light = new Light();//New一个电灯对象

 

            ICommand[] arr_Commands=new ICommand[4];int lint_Count=0;

 

            LightOnCommand lobj_LightOnCommand = new LightOnCommand(lobj_Light);//New一个命令对象:开灯

            arr_Commands[lint_Count++] = lobj_LightOnCommand;

 

            lobj_LightOnCommand = new LightOnCommand(lobj_Light);//这里为了方便起见,再New出一个开灯对象,实际开发中可以根据需要New出不同的命令,只要其实现了ICommand接口就行。

            arr_Commands[lint_Count++] = lobj_LightOnCommand;

 

            LightOffCommand lobj_LightOffCommand = new LightOffCommand(lobj_Light);//New一个命令对象:关灯

            arr_Commands[lint_Count++] = lobj_LightOffCommand;

 

            lobj_LightOffCommand = new LightOffCommand(lobj_Light);//New一个命令对象:关灯

            arr_Commands[lint_Count++] = lobj_LightOffCommand;

 

 

            lobj_Invoker.SetCommands(arr_Commands);//用命令组参数化Invoker

            lobj_Invoker.Execute();//执行命令

            lobj_Invoker.Undo();//撤消命令

 

            //可以再更换其它命令组来参数化Invoker,这里略。        

       

        }

 }

 

至此,命令模式完毕。

 

命令模式允许我们将动作封闭成命令对象,这样一来我们就可以随心所欲的存储、传递和调用它们。

命令模式所要解决的绝对不是单一命令这么简单,如果是仅仅是执行单一命令,那么作为Invoker(发出命令的对象)为什么不直接调用Receiver(命令执行者)Action方法,直接得到结果,而要费尽周折还要把命令这个“动作”封闭成对象,然后再由这个对象去调用Receiver中的Action,这不舍近求远吗?呵呵。

 

 

 

 

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值