• 深入浅出设计模式——命令模式(Command Pattern)


    模式动机

    在软件设计中,我们经常需要向某些对象发送请求,但是并不知道请求的接收者是谁,也不知道被请求的操作是哪个,我们只需在程序运行时指定具体的请求接收者即可,此时,可以使用命令模式来进行设计,使得请求发送者与请求接收者消除彼此之间的耦合,让对象之间的调用关系更加灵活。
    命令模式可以对发送者和接收者完全解耦,发送者与接收者之间没有直接引用关系,发送请求的对象只需要知道如何发送请求,而不必知道如何完成请求。这就是命令模式的模式动机。

    模式定义
    命令模式(Command Pattern):将一个请求封装为一个对象,从而使我们可用不同的请求对客户进行参数化;对请求排队或者记录请求日志,以及支持可撤销的操作。命令模式是一种对象行为型模式,其别名为动作(Action)模式或事务(Transaction)模式。
    Command Pattern: Encapsulate a request as an object, thereby letting you parameterize clients with different requests, queue or log requests, and support undoable operations.
    Frequency of use: medium high
    UML图

    模式结构
    命令模式包含如下角色:
    Command: 抽象命令类
    ConcreteCommand: 具体命令类
    Invoker: 调用者
    Receiver: 接收者
    Client:客户类

    模式分析
    命令模式的本质是对命令进行封装,将发出命令的责任和执行命令的责任分割开。
    每一个命令都是一个操作:请求的一方发出请求,要求执行一个操作;接收的一方收到请求,并执行操作。
    命令模式允许请求的一方和接收的一方独立开来,使得请求的一方不必知道接收请求的一方的接口,更不必知道请求是怎么被接收,以及操作是否被执行、何时被执行,以及是怎么被执行的。

    命令模式使请求本身成为一个对象,这个对象和其他对象一样可以被存储和传递。
    命令模式的关键在于引入了抽象命令接口,且发送者针对抽象命令接口编程,只有实现了抽象命令接口的具体命令才能与接收者相关联。

    模式实例与解析
    烤羊肉串引来的思考—命令模式
    体系结构

    Command: 抽象命令类 Command.cs

    namespace CommandPattern
    {
        //抽象命令类
        public abstract class Command
        {
            protected Barbecuer receiver;
            public Command(Barbecuer receiver)
            {
                this.receiver = receiver;
            }
            //执行命令
            abstract public void ExecuteCommand();
        }
    }

    ConcreteCommand: 具体命令类 BakeMuttonCommand.cs

    namespace CommandPattern
    {
        //烤羊肉串命令
        class BakeMuttonCommand : Command
        {
            public BakeMuttonCommand(Barbecuer receiver)
                : base(receiver)
            {
            }
            public override void ExecuteCommand()
            {
                receiver.BakeMutton();
            }
        }
    }

    BakeChickenWingCommand.cs

    namespace CommandPattern
    {
        //烤鸡翅命令
        class BakeChickenWingCommand : Command
        {
            public BakeChickenWingCommand(Barbecuer receiver)
                : base(receiver)
            {
            }
            public override void ExecuteCommand()
            {
                receiver.BakeChickenWing();
            }
        }
    }

    Invoker: 调用者 Waiter.cs

    using System;
    using System.Collections.Generic;
    
    namespace CommandPattern
    {
        //服务员
        public class Waiter
        {
            //增加存放具体命令的容器
            private IList<Command> orders = new List<Command>();
    
            //设置订单
            public void SetOrder(Command command)
            {
                if (command.ToString() == "CommandPattern.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.ExecuteCommand();            }
            }
        }
    }

    Receiver: 接收者 Barbecuer.cs

    using System;
    
    namespace CommandPattern
    {
        //烤肉串者
        public class Barbecuer
        {
            //烤羊串
            public void BakeMutton()
            {
                Console.WriteLine("烤羊肉串!");
            }
            public void BakeChickenWing()
            {
                Console.WriteLine("烤鸡翅!");
            }
        }
    }

    Client:客户类

    using System;
    
    namespace CommandPattern
    {
        class Program
        {
            static void Main(string[] args)
            {
                //开店前的准备
                Barbecuer boy = new Barbecuer();
                Command bakeMuttonCommand1 = new BakeMuttonCommand(boy);
                Command bakeMuttonCommand2 = new BakeMuttonCommand(boy);
                Command bakeChikenWingCommand1 = new BakeChickenWingCommand(boy);
                Waiter girl = new Waiter();
                //开门营业 顾客点菜
                girl.SetOrder(bakeMuttonCommand1);
                girl.SetOrder(bakeMuttonCommand2);
                girl.SetOrder(bakeChikenWingCommand1);
                //点菜完毕,通知厨房
                girl.Notify();
    
                Console.Read();
            }
        }
    }

    模式优缺点
    命令模式的优点
     降低系统的耦合度。
     新的命令可以很容易地加入到系统中。
     可以比较容易地设计一个命令队列和宏命令(组合命令)。
     可以方便地实现对请求的Undo和Redo。

    命令模式的缺点
     使用命令模式可能会导致某些系统有过多的具体命令类。因为针对每一个命令都需要设计一个具体命令类,因此某些系统可能需要大量具体命令类,这将影响命令模式的使用。

    模式适用环境
    在以下情况下可以使用命令模式:
     系统需要将请求调用者和请求接收者解耦,使得调用者和接收者不直接交互。
     系统需要在不同的时间指定请求、将请求排队和执行请求。
     系统需要支持命令的撤销(Undo)操作和恢复(Redo)操作。
     系统需要将一组操作组合在一起,即支持宏命令。

    【声明与感谢】
    本文,站在许多巨人的肩膀上,借鉴和引用了许多他人拥有版权的作品或著述,在此,对前人们的贡献致谢。并同时公布引用的内容、原作者或来源(一些来源于互联网的内容本人无法追述本源,深表遗憾)。

    【参考文献】
    《设计模式—可复用面向对象软件的基础》作者: [美] Erich Gamma / Richard Helm / Ralph Johnson / John Vlissides 译者: 李英军 / 马晓星 / 蔡敏 / 刘建中 等 机械工业出版社
    《重构—改善既有代码的设计》作者: Martin Fowler译者:候捷 中国电力出版社
    《敏捷软件开发—原则、模式与实践》作者: Robert C. Martin 清华大学出版社
    《程序员修炼之道—从小工到专家》作者: Andrew Hunt / David Thomas 电子工业出版社
    《Head First 设计模式》作者: 弗里曼 译者: O'Reilly Taiwan公司 中国电力出版社
    《设计模式之禅》 作者: 秦小波 机械工业出版社
    MSDN WebCast 《C#面向对象设计模式纵横谈》 讲师:李建忠
    刘伟. 设计模式. 北京:清华大学出版社, 2011.
    刘伟. 设计模式实训教程. 北京:清华大学出版社, 2012.
    《大话设计模式》 作者: 程杰 清华大学出版社
    《C#图解教程》作者: 索利斯 译者: 苏林 / 朱晔 人民邮电出版社
    《你必须知道的.NET》作者: 王涛
    《项目中的.NET》作者: 李天平 电子工业出版社
    《Microsoft .NET企业级应用架构设计》作者: (美)埃斯波西托等编著 译者: 陈黎夫
    http://www.dofactory.com/Patterns/Patterns.aspx .NET Design Patterns
    http://www.cnblogs.com/zhenyulu 博客作者:吕震宇
    http://www.cnblogs.com/terrylee 博客作者:李会军
    http://www.cnblogs.com/anlyren/ 博客作者:anlyren
    http://www.cnblogs.com/idior 博客作者:idior
    http://www.cnblogs.com/allenlooplee 博客作者:Allen lee
    http://blog.csdn.net/ai92 博客作者:ai92
    http://www.cnblogs.com/umlonline/ 博客作者:张传波
    http://www.cnblogs.com/lovecherry/ 博客作者:LoveCherry

  • 相关阅读:
    net 5 小常识试图及时编译
    C# CLR核心机制
    grpc 错误记录一下 掉坑里爬了三天
    基于docker 做的 kafka 集群 3分区
    efcore 查用命令
    vps检测
    IntelliJ Idea 2017 免费激活方法
    jQuery设置disabled属性与移除disabled属性
    Myeclipse中js文件中的乱码处理
    关于html中frameset下frame之间的交互,以及html中iframe和原html之间的交互
  • 原文地址:https://www.cnblogs.com/Bobby0322/p/4195240.html
Copyright © 2020-2023  润新知