• 设计模式(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();

    六、优缺点及适用场景

    优点:

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

    缺点:

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

    适用场景:

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

    补充:

    命令模式其实就是一对象发布命令,另外一个对象来执行。如果发出多个命令,其中一些命令发出后可以撤销,一些命令可以重复发出,等等复杂的操作。需要增加一个对象,对这些命令进行管理记录,并随时增加或者删除。同时如果新增加命令,不必对其他的对象造成过多的影响。

  • 相关阅读:
    multilabel-multiclass classifier
    关于zabbix _get返回Could not attach to pid的问题
    python导出环境依赖到req,txt文件中
    inode满的解决方法
    搞定面试官:咱们从头到尾再说一次 Java 垃圾回收
    SpringBoot项目,如何优雅的把接口参数中的空白值替换为null值?
    万万没想到,JVM内存区域的面试题也可以问的这么难?
    万万没想到,面试中,连 ClassLoader类加载器 也能问出这么多问题…..
    npm私服verdaccio报sha错误的解决方案
    配置SQL Server 2016无域AlwaysOn(转)
  • 原文地址:https://www.cnblogs.com/ysyn/p/4081408.html
Copyright © 2020-2023  润新知