• 定义

    • 将“请求”封装成对象,以便使用不同的请求、队列或者日志来参数化其他对象。命令模式也支持可撤销的操作。
    • 结构图:
  • 命令模式的角色划分:
    • Reciever(命令的接收者):接收命令,并知道如何进行必要的工作,实现具体的处理。任何类都可以当接收者。
    • Invoker(命令调用者):命令调用者持有一个命令对象,并在某个时间点调用命令对象的Execute()方法,将请求付诸实行。
    • Command(命令接口):Command为所有命令声明了一个接口。调用命令对象的Execute()方法,就可以让接收者进行相应的动作。这个接口也具备一个UnDo()方法,为了回滚动作使用,也可以不定义该方法。
    • ConcreteCommand(命令):ConcreateCommand定义了动作与接收者之间的绑定关系。调用者Execute()就可以发出请求,然后由ConcreateCommand调用就接收者的一个或者多个动作。
  • 应用示例:
    • 我们知道灯可以开、关,如果我们用程序去演示等的开关可以这么写:

      •  1 public class Program
         2 {
         3     public static void Main(string[] args)
         4     {
         5     Light light=new Light("light0001");
         6     // light turn on.
         7     light.On();
         8     // light turn off.
         9     light.Off();
        10     }
        11 }
        12
        13 public class Light
        14 {
        15     public string Name { get; set; }
        16
        17     public Light(string name)
        18     {
        19         this.Name = name;
        20     }
        21
        22     /// <summary>
        23     /// Turn on the light
        24     /// </summary>
        25     public void On()
        26     {
        27         Console.WriteLine("light:{0} is turn on.", this.Name);
        28     }
        29
        30     /// <summary>
        31     /// Turn off the light
        32     /// </summary>
        33     public void Off()
        34     {
        35         Console.WriteLine("light:{0} is turn off.", this.Name);
        36     }
        37 }

    • 上边的示例把灯的开、关动作调用都直接写在了Main的代码块中。但针对该例子这样写似乎没有看出有什么不妥的,但是如果是FTP的服务端接收命令解析时,我们把接收到的100左右个命令,分别定义出对应的函数到一个类中,这时就会发现这样做耦合度太高了,维护起来就不像单独On(),Off()两个动作这么轻松。
    • 试想,如果把FTP服务器端,接收到的命令拆分成不同的“命令”,有单一的“命令调用者”,这样会不会把结构划分的更清晰?

    • 备注:FTP向服务端请求命令:LS、DIR、MLS、MDIR、MKDIR、RMDIR

      LS有点像UNIX下的LS(LIST)命令:
      DIR相当于LS-L(LIST-LONG);
      MLS只是将远端某目 录下的文件存于LOCAL端的某文件里;
      MDIR相当于MLS;
      MKDIR像DOS下的MD(创建子目录)一样:
      RMDIR像DOS下的RD(删除子目录)一样。
    • 下边我们将上边的例子Light按照Command设计模式来改写,看下效果:
      • 命令接口:Command

        1 public interface ICommand
        2 {
        3
        4     void Execute();
        5
        6 }

      • 命令的接收者:Reciever
        •  1 public class Light
           2 {
           3     public string Name { get; set; }
           4
           5     public Light(string name)
           6     {
           7         this.Name = name;
           8     }
           9
          10     /// <summary>
          11     /// Turn on the light
          12     /// </summary>
          13     public void On()
          14     {
          15         Console.WriteLine("light:{0} is turn on.", this.Name);
          16     }
          17
          18     /// <summary>
          19     /// Turn off the light
          20     /// </summary>
          21     public void Off()
          22     {
          23         Console.WriteLine("light:{0} is turn off.", this.Name);
          24     }
          25 }

      • 命令的封装者:ConcreateCommand
         1 public class LightOnCommand : ICommand
         2 {
         3     private Light light;
         4
         5     public LightOnCommand(Light light)
         6     {
         7         this.light = light;
         8     }
         9
        10     public void Execute()
        11     {
        12         this.light.On();
        13     }
        14 }

      • 命令的封装者:ConcreateCommand
         1 public class LightOffCommand : ICommand
         2 {
         3     private Light light;
         4
         5     public LightOffCommand(Light light)
         6     {
         7         this.light = light;
         8     }
         9
        10     public void Execute()
        11     {
        12         this.light.Off();
        13     }
        14 }

      • 命令的封装者:命令的Invoker
         1 public class CommandControl
         2 {
         3     private ICommand command;
         4
         5     public CommandControl() { }
         6
         7     public void SetCommand(ICommand command)
         8     {
         9         this.command = command;
        10     }
        11
        12     public void ButtonPresssed()
        13     {
        14         this.command.Execute();
        15     }
        16 }

      • 客户端:client
         1 class Program
         2 {
         3     static void Main(string[] args)
         4     {
         5         CommandControl control = new CommandControl();
         6         Light light = new Light("light_001");
         7         LightOnCommand lightOn = new LightOnCommand(light);
         8         LightOffCommand lightOff = new LightOffCommand(light);
         9
        10         control.SetCommand(lightOn);
        11         control.ButtonPresssed();
        12
        13         control.SetCommand(lightOff);
        14         control.ButtonPresssed();
        15
        16         control.SetCommand(lightOn);
        17         control.ButtonPresssed();
        18
        19         control.SetCommand(lightOff);
        20         control.ButtonPresssed();
        21
        22         Console.ReadKey();
        23     }
        24 }

  • 开发中用到:
    •     
    • 怎么调用:
      •   
    • Command:
      •   
    • Reciever:
      •   
  • 应用场景:
    • 多级UnDo操作的应用场景;

      •   如何实现多层撤销操作?
      •   首先,不要只是记录最后一个被执行的命令,而使用一个堆栈记录操作过程的每一个命令。
      •   然后,不管什么时候操作了什么,都可以从堆栈中取出最上层的命令,然后调用它的UnDo()方法。
    •  命令可以将运算块打包(一个接收者和一组动作),让后将它传来传去,就像是一般的对象一样。现在,即使在命令对象被创建许久之后,运算依然可以被调用。事实上,它甚至可以在不同的线程中被调用。我们可以衍生一些应用,例如:日程安排(Scheduler)、线程池、工作队列等。
    • 日志请求:某些应用需要我们将所有的动作都记录在日志中,并能在系统死机之后,重新调用这些动作恢复到之前的状态。通过两个方法 Store(),Load(),命令模式就能够支持这一点。
  • 总结&优缺点:
    • 命令模式的实际应用还是挺广泛的,在FTP服务器端Socket接收到客户端命令请求,每个命令都需要做出对应的操作,为了业务的明细化,我们习惯上把这样的请求参数化,例如:SupperSocket.FTP中就是一个很好的命令模式的应用。
    • 优点:把‘请求’作为参数传递,将调用、参数、动作分开,解耦,业务更加清晰,代码逻辑更加明晰化,职责也更单一;
    • 缺点:子类划分的更多了,没出现一个新的请求,都需要new更多的类。

参考资料:《Head First 设计模式》

欢迎拍砖!请牛人们给指点。

(Command Pattern)命令模式相关推荐

  1. C++设计模式——命令模式(command pattern)

    一.原理讲解 别名动作(action),事务(transaction). 1.1意图 将一个请求封装为一个对象,从而使我们可用不同的请求对客户进行参数化,对请求排队或记录请求日志,以及支持可撤销的操作 ...

  2. 一文理解设计模式--命令模式(Command)

    命令模式(Command) 命令模式就是将命令包装成java对象,来保存命令历史记录和恢复上一个状态.重复执行命令,比如我们写代码的撤销(undo).取消撤销(redo) 适用场景 需要undo.re ...

  3. 命令模式(Command)

    18.命令模式(Command) 命令模式很好理解,举个例子,司令员下令让士兵去干件事情,从整个事情的角度来考虑,司令员的作用是,发出口令,口令经过传递,传到了士兵耳朵里,士兵去执行.这个过程好在,三 ...

  4. python 命令模式_python设计模式(十六):命令模式-阿里云开发者社区

    "行为请求者"与"行为实现者"通常呈现一种"紧耦合".但在某些场合,比如要对行为进行"记录.撤销/重做.事务"等处理,这 ...

  5. 设计模式之美——行为型3:迭代模式、访问者模式、命令模式、解释器模式、中介模式

    迭代器模式 迭代器模式的原理和实现 迭代器模式(Iterator Design Pattern),也叫作游标模式(Cursor Design Pattern). 迭代器模式.它用来遍历集合对象.这里说 ...

  6. 设计模式之命令模式、举例分析、通俗易懂

    1. 定义 命令模式(Command):将一个请求封装为一个对象,从而使你可用不同的请求对客户进行参数化;对请求排队或记录请求日志,以及支持可撤销的操作 简单来说,就是类似于消费者-服务员-厨师,消费 ...

  7. 游戏设计模式-命令模式

    游戏中,玩家的输入方式有很多种,例如键盘.鼠标等.玩家输入操作,游戏需要调用相应的逻辑,最简单的处理方式是: if (Input.GetKeyDown("Q")) Jump(); ...

  8. C++设计模式(8)——命令模式

    命令模式 亦称:动作.事务.Action.Transaction.Command 意图 命令模式是一种行为设计模式, 它可将请求转换为一个包含与请求相关的所有信息的独立对象. 该转换让你能根据不同的请 ...

  9. 命令模式——经营烧烤摊

      命令模式(Command)定义:将一个请求封装为一个对象,使发出请求的责任和执行请求的责任分割开.这样两者之间通过命令对象进行沟通,这样方便将命令对象进行储存.传递.调用.增加与管理.   例如去 ...

最新文章

  1. 某生鲜电商平台的监控模块设计
  2. mysql 导入创建表空间_说说在 Oracle11g 中如何创建表空间、创建用户并授权以及导入与导出数据...
  3. VTK:PolyData之SelectVisiblePoints
  4. SwiftUI之深入解析@StateObject、@ObservedObject和@EnvironmentObject的联系和区别
  5. python 内置函数转list_python 内置函数等的相互转换示例
  6. JPDL3.1规范手册
  7. echarts 树图样式美化_echarts2 tree树图自定义显示缩放大小、位置
  8. 蓝桥杯第九届省赛JAVA真题----螺旋折线
  9. c语言有啥简单的小程序,c语言-简单小程序-简单算法
  10. macOS搭建51单片机开发环境
  11. matlab 多变量求偏导,新手求解两个自变量的函数,求其中一个变量的偏导
  12. 软工网络15团队作业4——Alpha阶段敏捷冲刺之Scrum 冲刺博客(Day3)
  13. RSTP Proposal-Agreement
  14. Python学习推荐
  15. 博士毕业三年成为博导!他自述也曾想放弃科研
  16. 计算机网络路由器与路由协议配置,OSPF路由协议配置(计算机网络实验).doc
  17. “三高“Mysql - Mysql备份概览
  18. skynet 热更新
  19. KVM 虚拟化技术高级特性详解
  20. [HTML]书签怎么做?

热门文章

  1. 数据库名、实例名、数据库域名、全局数据库名、服务名 我也迷糊了
  2. 只“存活”9个月:Ubuntu 15.10今日停止支持
  3. 2.4 表单数据的验证
  4. HIBERNATE与 MYBATIS的对比
  5. [转载]了解Linux的进程与线程
  6. 黄聪:Wordpress程序Mysql查询导致CPU100%,页面错误增量飙高解决方案
  7. RTMP中FLV流到标准h264、aac的转换
  8. ASP.NET 程序中常用的三十三种代码
  9. SpringCloud Ribbon负载均衡介绍及使用
  10. sarscape 将dem文件转化成stl_STL文件,一种前处理网格划分技术??