• 设计模式(十五)—— 命令模式


    模式简介


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

    在一些系统功能设计的时候,需要向某个对象发送请求,但是并不知道请求的接收者以及被请求的具体操作,而是在程序运行时指定具体的请求接收者。这段话比较抽象,下面通过一个实际生活中的例子来帮助大家理解。

    假如我们设计了一款虚拟遥控器,用来控制智能家居电器的开关。在产品设计时我们并不知道每个按钮具体对应到哪样家居电器,而是根据用户选择,在软件运行时绑定具体的操作。这样一来,我们就需要在产品设计时将请求调用者(遥控器)与请求接受者(智能家居)解耦,使得调用者和接收者不直接交互

    结构说明


    角色说明

    • ICommand

    命令接口,包含一个执行操作的方法。

    • ConcreteCommand

    具体命令类,包含一个接收者对象,并调用接收者对象以实现Execute方法。

    • Receiver

    接收者,知道如何执行一个操作以满足客户端传来的请求。

    • Invoker

    调用者,要求该命令执行这个请求。

    结构代码

    声明接收者Receiver,包含一个Action方法。

    class Receiver
    {
        public void Action()
        {
            Console.WriteLine("called Receiver.Action()");
        }
    }
    

    声明ICommand接口以及具体命令类ConcreteCommand,包含一个Receiver类型的成员。

    interface ICommand
    {
        void Execute();
    }
    
    class ConcreteCommand : ICommand
    {
        private Receiver _receiver;
        public ConcreteCommand(Receiver receiver)
        {
            _receiver = receiver;
        }
        public void Execute()
        {
            _receiver.Action();
        }
    }
    

    声明调用者,提供SetCommand方法设置命令,并提供Call方法执行该命令。

    class Invoker
    {
        private ICommand _command;
        public void SetCommand(ICommand command)
        {
            _command = command;
        }
    
        public void Call()
        {
            _command.Execute();
        }
    
    }
    

    客户端调用:

    class Program
    {
        static void Main(string[] args)
        {
            Receiver receiver = new Receiver();
            ConcreteCommand concreteCommand = new ConcreteCommand(receiver);
            Invoker invoker = new Invoker();
            invoker.SetCommand(concreteCommand);
            invoker.Call();
            Console.ReadLine();
        }
    }
    

    输出结果:

    工作原理

    客户端创建一个ConcreteCommand对象并指定它的Reciever对象,再创建一个Invoker对象,存储该ConcreteCommand对象。Invoker通过ConcreteCommand的Execute方法提交请求,ConcreteCommand对象将请求传递给Receiver最终执行。

    示例分析


    本节我们通过命令模式来实现虚拟遥控器的示例。首先创建两个Receiver:Light和TV,它们都提供各自打开/关闭的方法。

    class Light
    {
        public void TurnOn()
        {
            Console.WriteLine("Light is turning on");
        }
    
        public void TurnOff()
        {
            Console.WriteLine("Light is turning off");
        }
    }
    
    class TV
    {
        public void TurnOn()
        {
            Console.WriteLine("TV is Turining on");
        }
        public void TurnOff()
        {
            Console.WriteLine("TV is Turning off");
        }
    }
    

    创建ICommand接口,并分别实现开灯、关灯、打开电视以及关闭电视四个命令。

    interface ICommand
    {
        void Execute();
    }
    
    class LightTurnOnCommand : ICommand
    {
        private Light _light;
        public LightTurnOnCommand(Light light)
        {
            _light = light;
        }
        public void Execute()
        {
            _light.TurnOn();
        }
    }
    
    class LightTurnOffCommand : ICommand
    {
        private Light _light;
        public LightTurnOffCommand(Light light)
        {
            _light = light;
        }
        public void Execute()
        {
            _light.TurnOff();
        }
    }
    
    class TVTurnOnCommand : ICommand
    {
        private TV _tv;
        public TVTurnOnCommand(TV tv)
        {
            _tv = tv;
        }
        public void Execute()
        {
            _tv.TurnOn();
        }
    }
    
    class TVTurnOffCommand : ICommand
    {
        private TV _tv;
        public TVTurnOffCommand(TV tv)
        {
            _tv = tv;
        }
        public void Execute()
        {
            _tv.TurnOff();
        }
    }
    

    创建遥控器RemoteController,包含一个命令集合,提供AddCommand方法向command集合添加命令。

    class RemoteController
    {
        private List<ICommand> _commandList = new List<ICommand>();
        public void AddCommand(ICommand command)
        {
            _commandList.Add(command);
        }
        public void Call(int i)
        {
            _commandList[i].Execute();
        }
    }
    

    下面我们在客户端进行配置,首先创建一个remoteController遥控器,并绑定相应的操作,1->开灯,2->关灯,3->打开电视,4->关闭电视,99->退出遥控器。

    class Program
    {
        static void Main(string[] args)
        {
            RemoteController remoteController = new RemoteController();
            Light light = new Light();
            LightTurnOnCommand lightTurnOn = new LightTurnOnCommand(light);
            LightTurnOffCommand lightTurnOff = new LightTurnOffCommand(light);
            TV tv = new TV();
            TVTurnOnCommand tvTurnOn = new TVTurnOnCommand(tv);
            TVTurnOffCommand tvTurnOff = new TVTurnOffCommand(tv);
            remoteController.AddCommand(lightTurnOn);
            remoteController.AddCommand(lightTurnOff);
            remoteController.AddCommand(tvTurnOn);
            remoteController.AddCommand(tvTurnOff);
    
            int input = 0;
            do
            {
                Console.WriteLine("Please enter your command(enter 99 to exit):");
                input = Convert.ToInt32(Console.ReadLine());
                if (input == 99)
                {
                    Console.WriteLine("Exit!");
                    break;
                }
                remoteController.Call(input - 1);
            } while (input != 99);
    
            Console.ReadLine();
        }
    }
    

    输出结果:

    适用场景


    • 将请求调用者和请求接受者解耦,使得调用者和接收者不直接交互。

    • 在不同的时刻指定、排列和执行请求。

    • 支持命令的撤消及恢复操作。

    • 支持将一组操作组合在一起,在适当时刻执行。

  • 相关阅读:
    Mysql 数据库高级
    Mysql 数据库
    并发编程
    网络编程
    1113
    1112
    P相遇游戏
    中位数
    PETS
    打暴力程序的正确做法
  • 原文地址:https://www.cnblogs.com/Answer-Geng/p/9215298.html
Copyright © 2020-2023  润新知