首页 > 代码库 > 设计模式(10)---命令模式

设计模式(10)---命令模式

一、引言:

  路边有一个烤肉摊,有一位老板负责给客人烧烤食物。如果客人很少,老板都能准确记住大家的要求,随着客人的增多,要求越来越多,老板很难满足大家要求,老板应该怎么办?

首先说明为什么客人多了,老板满足不了大家的要求,因为“用程序猿的话说是因为:紧耦合”。松耦合就能很好的解决此问题,也就是本文介绍的命令模式。先给出紧耦合代码:

class Program    {        static void Main(string[] args)        {            Receiver receiver = new Receiver();            receiver.BakeChickenWing();            Console.Read();        }    }    public class Receiver//boss    {        public void BakeMutton()        {            Console.WriteLine("bake mutton");        }        public void BakeChickenWing()        {            Console.WriteLine("bake chickenwing");        }    }
View Code

 

二、定义:

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

解释:将请求命令封装为一个对象,并用日志记录下来,其中它支持命令撤销功能。

 

三、UML图及基本代码:

基本代码:

class Receicer    {        public void Action()        {            Console.WriteLine("执行请求");        }    }    abstract class Command    {        protected Receicer receiver;        public Command(Receicer receiver)        {            this.receiver = receiver;        }        abstract public void Execute();    }    class ConcreteCommand : Command    {        public ConcreteCommand(Receicer receiver)            : base(receiver)        { }        public override void Execute()        {            receiver.Action();        }    }    class Invoker    {        private Command command;        public void SetCommand(Command command)        {            this.command = command;        }        public void ExecuteCommand()        {            command.Execute();        }    }

调用:

Receicer receiver = new Receicer();            Command command = new ConcreteCommand(receiver);            Invoker invoker = new Invoker();
invoker.SetCommand(command);

invoker.ExecuteCommand();

解释:映射客人到酒店就餐。Receiver是命令的接收者,相当于酒店中的大厨;Command命令抽象类,ConcreteCommand是具体的命令,相当于点菜请求,命令中应该包含命令的接收者。Invoke是命令的传达者,相当于酒店的服务员,负责记录客人点菜请求,并传达给后厨。

 

四、举例说明:

 学校高一学生进行军训,校长发布让学生跑10000米的命令。整个过程:校长发布命令给军训教官,教官传达校长命令给学生,学生接收到命令后执行相应的操作。在下面实例中,Receiver是学生,操作跑10000米的命令。Command是命令,必需知道命令的接收者。Drillmaster是教官,教官必需知道命令是什么,并传达命令。

//校长发布学生跑1000米的命令,教官传达此命令给学生,学生是命令的接收者    //客户端:校长,命令的发出者必须知道具体的命令、接受者、传达命令者    class Program    {        static void Main(string[] args)        {            Receiver receiver = new Receiver();            Command command = new ConcreteCommand(receiver);            Drillmaster drillmaster = new Drillmaster(command);            drillmaster.ExecuteCommand();            Console.Read();        }    }    //命令接收者    public class Receiver    {        public void Run1000Meters()        {            Console.WriteLine("跑10000米");        }    }    //抽象命令    public abstract class Command    {        protected Receiver receiver;        public Command(Receiver receiver)        {            this.receiver = receiver;        }        public abstract void Action();    }    //具体的命令,必须知道命令接受者    public class ConcreteCommand : Command    {        public ConcreteCommand(Receiver receiver)            : base(receiver)        { }        public override void Action()        {            receiver.Run1000Meters();        }    }    //教官:命令的传达者,负责调用命令对象的方法来保证命令执行    public class Drillmaster    {        public Command command;        public Drillmaster(Command command)        {            this.command = command;        }        public void ExecuteCommand()        {            command.Action();        }    }
View Code

 

五、解决引言中的问题

客人点菜命令的接收者,老板(大厨):

public class Receiver    {        public void BakeMutton()        {            Console.WriteLine("bake mutton");        }        public void BakeChickenWing()        {            Console.WriteLine("bake chickenwing");        }    }

 

点菜命令:

public abstract class Command    {        protected Receiver receiver;        public Command(Receiver receiver)        {            this.receiver = receiver;        }        abstract public void Execute();    }    class ConcreteCommand1 : Command    {        public ConcreteCommand1(Receiver receiver)            : base(receiver)        { }        public override void Execute()        {            receiver.BakeMutton();        }    }    class ConcreteCommand2 : Command    {        public ConcreteCommand2(Receiver receiver)            : base(receiver)        { }        public override void Execute()        {            receiver.BakeChickenWing();        }    }

 

增加一个服务生,负责记录客人点菜命令,并传达给大厨。点菜命令可以进行增加或取消操作。

public class Invoker    {        private IList<Command> commands = new List<Command>();        public void AddCommand(Command command)        {            commands.Add(command);            Console.WriteLine("增加订单" + command.ToString());        }        public void CancelCommand(Command command)        {            commands.Remove(command);            Console.WriteLine("取消订单" + command.ToString());        }        public void ExecuteCommand()        {            foreach (Command command in commands)            {                command.Execute();            }        }    }

 

客户端调用:

Receiver receiver = new Receiver();            Command command1 = new ConcreteCommand1(receiver);            Command command2 = new ConcreteCommand2(receiver);            Invoker invoker = new Invoker();            invoker.AddCommand(command1);            invoker.AddCommand(command2);            invoker.CancelCommand(command1);            invoker.ExecuteCommand();

 

六、优缺点及适用场景

优点:

比较容易的设计一个命令队列;在需要的情况下,可以比较容易的将命令计入日志;允许接收请求的一方决定是否要否决请求;比较容易的对命令实现撤销和重做;由于加入新的具体命令类不影响其他的类,因此增加新的具体命令类比较容易。

缺点:

可能会导致系统具有过多的具体命令类。

 

适用场景:

个人理解:基本上能表现其优点的地方都可以使用命令模式。

设计模式(10)---命令模式