• 二十三种设计模式[14]


    前言

           命令模式,对象行为型模式的一种。它帮助我们将功能的调用者与实现者之间解耦(甚至完全解耦)。调用者与实现者之间并不是直接引用关系,调用者只需要知道如何发送当前功能的请求即可,而不用关心该请求由谁在何时完成。

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

                                                                                                                                                                 ——《设计模式 - 可复用的面向对象软件》

    结构

    Connand_1

    • Command(命令类接口):声明执行操作的接口;
    • ConcreteCommand(命令类):Command接口的实现,用来调用具体的实现;
    • Invoker(调用者):用来控制命令的执行,个人理解为Command的代理类;
    • Receiver(接收者):功能具体的实现,由ConcreteCommand调用;

    示例

           考虑一个能够控制各种智能家电的App。在这个App中用户可以随意添加按钮来控制某个家电的某个功能。也就是说当我们开发这个App时并不能确定用户添加的按钮是控制什么家电执行什么功能。现在我们使用命令模式来模拟

    Connand_2

    /// <summary>
    /// 命令的接收者
    /// </summary>
    public class Television
    {
        public void Open()
        {
            Console.WriteLine("打开电视机");
        }
    
        public void Close()
        {
            Console.WriteLine("关闭电视机");
        }
    }
    
    /// <summary>
    /// 命令接口
    /// </summary>
    public interface ICommand
    {
        void Execute();
    }
    
    /// <summary>
    /// 开机命令
    /// </summary>
    public class TvOpenCommand : ICommand
    {
        private Television _tv = null;
    
        public TvOpenCommand(Television tv)
        {
            this._tv = tv;
        }
    
        public void Execute()
        {
            this._tv.Open();
        }
    }
    
    /// <summary>
    /// 关机命令
    /// </summary>
    public class TvCloseCommand : ICommand
    {
        private Television _tv = null;
    
        public TvCloseCommand(Television tv)
        {
            this._tv = tv;
        }
    
        public void Execute()
        {
            this._tv.Close();
        }
    }
    
    /// <summary>
    /// 命令的调用者
    /// </summary>
    public class Button
    {
        public ICommand Command { set; get; }
    
        public Button(ICommand command)
        {
            this.Command = command;
        }
    
        public void Click()
        {
            this.Command.Execute();
        }
    }
    
    static void Main(string[] args)
    {            
        Television tv = new Television();           //创建电视机对象(命令的接收者)
    
        ICommand tvOpen = new TvOpenCommand(tv);    //创建开机命令
        ICommand tvClose = new TvCloseCommand(tv);  //创建关机命令
    
        Button button = new Button(tvOpen);         //创建开机按钮(命令的调用者)
        button.Click();                             //执行命令
    
        button.Command = tvClose;                   //将按钮功能变更为关机
        button.Click();                             //执行命令
    
        Console.ReadKey();
    }

           在上述示例中,Button类充当调用者角色,Television类充当接收者角色。我们为Television类中的每一个函数都创建了命令类,不同的命令类决定了不同的操作,而该操作具体的实现由接收者完成。作为调用者的Button类并不知道它使用了哪个类执行了哪些操作,它只知道在它的Click函数中调用了ICommand接口的Execute函数。这就体现了命令模式的本质,将调用者与接收者解耦

    • 命令宏

             在日常生活中,我们往往希望通过一个按钮来执行一系列操作(比如一键打开电视和空调)。这个时候可以将命令模式与组合模式一同使用来实现一个命令宏(又称命令队列)。

    Connand_3

    /// <summary>
    /// 命令的接收者
    /// </summary>
    public class Television
    {
        public void Open()
        {
            Console.WriteLine("打开电视机");
        }
    
        public void Close()
        {
            Console.WriteLine("关闭电视机");
        }
    }
    
    /// <summary>
    /// 命令接收者
    /// </summary>
    public class AirConditioner
    {
        public void Open()
        {
            Console.WriteLine("打开空调");
        }
    
        public void Close()
        {
            Console.WriteLine("关闭空调");
        }
    }
    
    /// <summary>
    /// 命令接口
    /// </summary>
    public interface ICommand
    {
        void Execute();
    }
    
    /// <summary>
    /// 开机命令
    /// </summary>
    public class TvOpenCommand : ICommand
    {
        private Television _tv = null;
    
        public TvOpenCommand(Television tv)
        {
            this._tv = tv;
        }
    
        public void Execute()
        {
            this._tv.Open();
        }
    }
    
    /// <summary>
    /// 关机命令
    /// </summary>
    public class TvCloseCommand : ICommand
    {
        private Television _tv = null;
    
        public TvCloseCommand(Television t
        {
            this._tv = tv;
        }
    
        public void Execute()
        {
            this._tv.Close();
        }
    }
    
    /// <summary>
    /// 开机命令
    /// </summary>
    public class AcOpenCommand : ICommand
    {
        private AirConditioner _ac = null;
    
        public AcOpenCommand(AirConditioner ac)
        {
            this._ac = ac;
        }
    
        public void Execute()
        {
            this._ac.Open();
        }
    }
    
    /// <summary>
    /// 关机命令
    /// </summary>
    public class AcCloseCommand : ICommand
    {
        private AirConditioner _ac = null;
    
        public AcCloseCommand(AirConditioner ac)
        {
            this._ac = ac;
        }
    
        public void Execute()
        {
            this._ac.Close();
        }
    }
    
    /// <summary>
    /// 命令宏
    /// </summary>
    public class MacorCommand : ICommand
    {
        public List<ICommand> Commands { set; get; } = new List<ICommand>();
    
        public void Execute()
        {
            foreach (var command in this.Commands)
            {
                command.Execute();
            }
        }
    }
    
    /// <summary>
    /// 命令的调用者
    /// </summary>
    public class Button
    {
        public ICommand Command { set; get; }
    
        public Button(ICommand command)
        {
            this.Command = command;
        }
    
        public void Click()
        {
            this.Command.Execute();
        }
    }
    
    static void Main(string[] args)
    {
        Television tv = new Television();                       //电视对象(命令接收者)
        AirConditioner ac = new AirConditioner();               //空调对象(命令接收者)
    
        TvOpenCommand tvOpenCommand = new TvOpenCommand(tv);    //电视开机命令
        AcOpenCommand acOpenCommand = new AcOpenCommand(ac);    //空调开机命令
        MacorCommand macorCommand = new MacorCommand();         //宏命令
        macorCommand.Commands.Add(tvOpenCommand);               //设置宏命令
        macorCommand.Commands.Add(acOpenCommand);               //设置宏命令
    
        Button button = new Button(macorCommand);               //创建宏按钮
        button.Click();                                         //执行命令
    
        Console.ReadKey();
    }

          示例中创建一个聚合了ICommand接口的MacorCommand类充当组合模式中的Compsite角色,用来存储一系列的命令。它的存在能够使调用者一次执行多个使用不同接收者的命令。

          对于命令模式的扩展还有很多,比如请求日志和逆向操作(撤销)等等。这里就不一一举例了。

    总结

           命令模式的核心思想是将一个请求封装,将一个请求命令的发出(调用)和接收处理分割开,达到将调用者与接收者解耦的目的。命令模式中的每个命令类都保持了一个很小的颗粒度,因为它只封装了一个接收类中的一个函数。好处是在开发的过程中调用者不必关心也不知道具体执行的函数,保证了调用者与接收者的松耦合状态,以便更好的控制和应对各种变化。同时也意味着令类需要封装的函数越多命令类也就越多,存在类爆炸的风险。

           以上,就是我对命令模式的理解,希望对你有所帮助。

           示例源码:https://gitee.com/wxingChen/DesignPatternsPractice

           系列汇总:https://www.cnblogs.com/wxingchen/p/10031592.html

           本文著作权归本人所有,如需转载请标明本文链接(https://www.cnblogs.com/wxingchen/p/10031585.html)

  • 相关阅读:
    Vue Router基础
    Bootstrap4入门
    React性能优化
    Koa,React和socket.io
    RN-进阶
    RN-入门基础
    RN-环境配置
    React高级指引
    React基础概念
    实现A-Z滑动检索菜单
  • 原文地址:https://www.cnblogs.com/wxingchen/p/10031585.html
Copyright © 2020-2023  润新知