命令模式:

命令模式(Command)(行动(Action)模式或交易(Transaction)模式。),是一种数据驱动的设计模式,它属于行为型模式,将一个请求封装成一个对象,从而使你可用不同的请求对客户进行参数化,对请求排队或者记录请求日志,以及支持可撤销的操作。

命令模式是对命令的封装。命令模式把发出命令的责任和执行命令的责任分割开,委派给不同的对象。

命令允许请求的一方和接收请求的一方能够独立演化,从而有以下的优点:

命令模式使新的命令很容易地被加入到系统里。
允许接收请求的一方决定是否要否决(Veto)请求。
能较容易地设计一个命令队列。
可以容易地实现对请求的Undo和Redo。
在需要的情况下,可以较容易地将命令记入日志。
命令模式把请求一个操作的对象与知道怎么执行一个操作的对象分割开。
命令类与其他任何别的类一样,可以修改和推广。

缺点:使用命令模式可能会导致某些系统有过多的具体命令类。

命令模式UML结构图:

例(烤羊肉串):

UML图:

代码实现:

  //服务员
    public class Waiter
    {
        private IList<Command> orders = new List<Command>();  //命令序列

        //设置订单
        public void SetOrder(Command command)
        {
            if (command.ToString() == "命令模式.BakeChickenWingCommand")
            {
                Console.WriteLine("服务员:鸡翅没有了,请点别的烧烤。");
            }
            else
            {
                orders.Add(command);
                Console.WriteLine("增加订单:" + command.ToString() + "  时间:" + DateTime.Now.ToString());
            }
        }

        //取消订单
        public void CancelOrder(Command command)
        {
            orders.Remove(command);
            Console.WriteLine("取消订单:" + command.ToString() + "  时间:" + DateTime.Now.ToString());
        }

        //通知全部执行
        public void Notify()
        {
            foreach (Command cmd in orders)
            {
                cmd.ExcuteCommand();
            }
        }
    }

    //抽象命令
    public abstract class Command
    {
        protected Barbecuer receiver;

        public Command(Barbecuer receiver)
        {
            this.receiver = receiver;
        }

        //执行命令
        abstract public void ExcuteCommand();
    }

    //烤羊肉串命令
    class BakeMuttonCommand : Command
    {
        public BakeMuttonCommand(Barbecuer receiver)
            : base(receiver)
        { }

        public override void ExcuteCommand()
        {
            receiver.BakeMutton();
        }
    }

    //烤鸡翅命令
    class BakeChickenWingCommand : Command
    {
        public BakeChickenWingCommand(Barbecuer receiver)
            : base(receiver)
        { }

        public override void ExcuteCommand()
        {
            receiver.BakeChickenWing();
        }
    }

    //烤肉串者
    public class Barbecuer
    {
        public void BakeMutton()
        {
            Console.WriteLine("烤羊肉串!");
        }

        public void BakeChickenWing()
        {
            Console.WriteLine("烤鸡翅!");
        }
    }

 	class Program
    {
        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();

        }
    }

例(计算器——允许执行undo与redo):

UML图:

代码实现:

	abstract class Command
    {
        // Methods 
        abstract public void Execute();
        abstract public void UnExecute();
    }

    class CalculatorCommand : Command
    {
        char @operator;  //"operator"在C#中是关键词,所以在前面添加一个"@"将其变为标识符
        int operand;
        Calculator calculator;
        public CalculatorCommand(Calculator calculator, char @operator, int operand)
        {
            this.calculator = calculator;
            this.@operator = @operator;
            this.operand = operand;
        }
        public char Operator
        {
            set { @operator = value; }
        }
        public int Operand
        {
            set { operand = value; }
        }
        override public void Execute()
        {
            calculator.Operation(@operator, operand);
        }
        override public void UnExecute()
        {
            calculator.Operation(Undo(@operator), operand);
        }
        private char Undo(char @operator)
        {
            char undo = ' ';
            switch (@operator)
            {
                case '+': undo = '-'; break;
                case '-': undo = '+'; break;
                case '*': undo = '/'; break;
                case '/': undo = '*'; break;
            }
            return undo;
        }
    }

    class Calculator
    {
        private int total = 0;
        public void Operation(char @operator, int operand)
        {
            switch (@operator)
            {
                case '+': total += operand; break;
                case '-': total -= operand; break;
                case '*': total *= operand; break;
                case '/': total /= operand; break;
            }
            Console.WriteLine("Total = {0} (following {1} {2})",
            total, @operator, operand);
        }
    }

    class User
    {
        private Calculator calculator = new Calculator();
        private ArrayList commands = new ArrayList();
        private int current = 0;
        public void Redo(int levels)
        {
            Console.WriteLine("---- Redo {0} levels ", levels);

            for (int i = 0; i < levels; i++)
                if (current < commands.Count - 1)
                    ((Command)commands[current++]).Execute();
        }
        public void Undo(int levels)
        {
            Console.WriteLine("---- Undo {0} levels ", levels);
            for (int i = 0; i < levels; i++)
                if (current > 0)
                    ((Command)commands[--current]).UnExecute();
        }
        public void Compute(char @operator, int operand)
        {
            Command command = new CalculatorCommand(
            calculator, @operator, operand);
            command.Execute();
            commands.Add(command);
            current++;
        }
    }

    public class Client
    {
        static void Main(string[] args)
        {
            User user = new User();
            user.Compute('+', 100);
            user.Compute('-', 50);
            user.Compute('*', 10);
            user.Compute('/', 2);
            user.Undo(4);
            user.Redo(3);
        }
    }