代码改变世界

Command命令模式

2012-08-22 09:36  Mike.Jiang  阅读(521)  评论(0编辑  收藏  举报

1 GOF中的定义

1.1 意图

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

1.2

结构图

2 初步理解方法调用

代码:

View Code
    public class ClassA
    {
        public int Compute() 
        {
            Calc c = new Calc();
            return c.Execute();
        }
    }

    public class Calc
    {
        public int Execute()
        {
            return 3;
        }
    }

说明:

类ClassA中的直接调用Calc类的Add方法,Class是方法的调用者,Calc是方法的执行者。这样的代码我们每天都在写,没有什么问题。但是当我们遇到这样的需求“对请求排队或记录请求日志,以及支持可撤消的操作”,即在调用某个方法是对方法进行排队调用。因为方法是没有类型的,而要达到对请求排队,就需要让方法先具有类型,即将行为抽象。

3 重构2中的代码

代码:

View Code
    /// <summary>
    /// 抽象行为为接口,使方法具有类型。这样就可以在调用类ClassA中声明IList<ICommand> cmdList = new List<ICommand>(),
    /// 然后就可以继续实现对请的排队、记录日志、添加修改或移除请求了
    /// </summary>
    public interface ICommand
    {
        int Execute();
    }

public class ConcreteCommand2 : ICommand
    {
        private int a;

        public int A
        {
            get { return a; }
            set { a = value; }
        }

        private int b;

        public int B
        {
            get { return b; }
            set { b = value; }
        }

        public int Execute()
        {
            return A-B;
        }
    }

public class ConcreteCommand1 : ICommand
    {
        private int a;

        public int A
        {
            get { return a; }
            set { a = value; }
        }

        private int b;

        public int B
        {
            get { return b; }
            set { b = value; }
        }

        public int Execute()
        {
            return A+B;
        }
    }

    public class Invoker
    {
        private IList<ICommand> cmdList = new List<ICommand>();

        public void AddCmd(ICommand cmd) 
        {
            cmdList.Add(cmd);
        }
        public void Compute() 
        {
            foreach (ICommand cmd in cmdList) 
            {
                Console.WriteLine(cmd.Execute());
            }
        }
    }

    static void Main(string[] args)
        {
            Invoker invoker = new Invoker();
            ConcreteCommand1 cmd1 = new ConcreteCommand1();
            cmd1.A = 10;
            cmd1.B = 10;
            invoker.AddCmd(cmd1);

            ConcreteCommand2 cmd2 = new ConcreteCommand2();
            cmd2.A = 20;
            cmd2.B = 20;
            invoker.AddCmd(cmd2);
            invoker.Compute();
        }

结构图:

说明:

代码写到这已经做到了GOF中的要求,但现在与GOF中的类图还有很大的区别。这只是应用场景的不同,因为具体实现的命令的方法,已在其它类中实现了。

4 重构3中的代码

代码:

View Code
    /// <summary>
    /// 抽象行为为接口,使方法具有类型。这样就可以在调用类ClassA中声明IList<ICommand> cmdList = new List<ICommand>(),
    /// 然后就可以继续实现对请的排队、记录日志、添加修改或移除请求了
    /// </summary>
    public interface ICommand
    {
        int Execute();
    }

    public class ConcreteCommand1 : ICommand
    {
        private Receiver1 receiver;

        public ConcreteCommand1(Receiver1 receiver) 
        {
            this.receiver = receiver;
        }
        public int Execute()
        {
            return receiver.Sub();
        }
    }

    public class ConcreteCommand2 : ICommand
    {
        private Receiver2 receiver;

        public ConcreteCommand2(Receiver2 receiver)
        {
            this.receiver = receiver;
        }
        public int Execute()
        {
            return receiver.Add();
        }
    }

    public class Receiver1
    {
        private int a;

        public int A
        {
            get { return a; }
            set { a = value; }
        }

        private int b;

        public int B
        {
            get { return b; }
            set { b = value; }
        }

        public int Sub()
        {
            return A - B;
        }
    }

    public class Receiver2
    {
        private int a;

        public int A
        {
            get { return a; }
            set { a = value; }
        }

        private int b;

        public int B
        {
            get { return b; }
            set { b = value; }
        }

        public int Add()
        {
            return A + B;
        }
    }


    public class Invoker
    {
        private IList<ICommand> cmdList = new List<ICommand>();

        public void AddCmd(ICommand cmd) 
        {
            cmdList.Add(cmd);
        }
        public void Compute() 
        {
            foreach (ICommand cmd in cmdList) 
            {
                Console.WriteLine(cmd.Execute());
            }
        }
    }

        static void Main(string[] args)
        {
            Invoker invoker = new Invoker();
            Receiver1 rec1 = new Receiver1();
            rec1.A = 10;
            rec1.B = 10;
            ConcreteCommand1 cmd1 = new ConcreteCommand1(rec1);
            invoker.AddCmd(cmd1);

            Receiver2 rec2 = new Receiver2();
            rec2.A = 20;
            rec2.B = 20;
            ConcreteCommand2 cmd2 = new ConcreteCommand2(rec2);
            invoker.AddCmd(cmd2);
            invoker.Compute();
        }

结构图:

说明:

加了一个Receiver类(已具体实现了某个方法的类)。ConreteCommand只需一个Receiver类的某个具体方法,而不需要其它方法,在图2中加入适配器模式。