命令模式的定义

命令模式属于对象的行为型模式。命令模式是把一个操作或者行为抽象为一个对象中,通过对命令的抽象化来使得发出命令的责任和执行命令的责任分隔开。命令模式的实现可以提供命令的撤销和恢复功能。

  • Receive接收者角色
          该角色就是干活的角色,命令传递到这里是应该被执行的。 
  • Command命令角色
          需要执行的所有命令都这里声明。 
  • Invoker调用这角色
          接收到命令,并执行命令。
 
具体命令模式的实现代码如下所示:
namespace ConsoleApplication1
{
/// <summary>
/// 干活者的抽象
/// </summary>
public abstract class Receiver
{
//抽象接收者,定义每个接收者都必须完成的业务
public abstract void doSomething();
}
/// <summary>
/// 具体干活的类
/// </summary>
public class ConcrateReciver1 : Receiver
{
//每个接收者都必须处理一定的业务逻辑
public override void doSomething()
{ }
}
/// <summary>
/// 具体干活的类
/// </summary>
public class ConcrateReciver2 : Receiver
{
//每个接收者都必须处理一定的业务逻辑
public override void doSomething()
{
}
}
/// <summary>
/// 命令的抽象 命令里包含干活者的对象
/// </summary>
public abstract class Command
{
//每个命令类都必须有一个执行命令的方法
public abstract void execute();
}
public class ConcreteCommand1 : Command
{
//对哪个Receiver类进行命令处理
private Receiver receiver;
//构造函数传递接收者
public ConcreteCommand1(Receiver _receiver)
{
this.receiver = _receiver;
}
//必须实现一个命令
public override void execute()
{
//业务处理
this.receiver.doSomething();
}
}
public class ConcreteCommand2 : Command
{
//对哪个Receiver类进行命令处理
private Receiver receiver;
//构造函数传递接收者
public ConcreteCommand2(Receiver _receiver)
{
this.receiver = _receiver;
}
//必须实现一个命令
public override void execute()
{
//业务处理
this.receiver.doSomething();
}
}
/// <summary>
/// 调度者的抽象,主要负责接收命令和执行命令
/// </summary>
public class Invoker
{
private Command command;
//接收命令
public Command Command
{
set { command = value; }
}
//执行命令
public void action()
{
this.command.execute();
}
}
class Program
{
static void Main(string[] args)
{
//首先声明调用者Invoker
Invoker invoker = new Invoker();
//定义接收者
Receiver receiver = new ConcrateReciver1();
//定义一个发送给接收者的命令
Command command = new ConcreteCommand1(receiver);
//把命令交个调用者去执行
invoker.Command = command;
invoker.action();
Console.ReadLine();
}
}
}

命令模式的优缺点

优点:
  • 类间解耦
          调用者角色与接收者之间没有任何依赖关系,调用者实现功能时只需要调用Command抽象类的execute方法就可以,不需要了解到底是哪个接收者执行。 
  • 可扩展性
          Command的子类可以非常容易地扩展,而调用者Invoker和高层次的模块Client不产生严重的代码耦合。 
  • 命令模式结合其他模式会更优秀
          命令模式可以结合责任链模式,实现命令族解析任务;结合模板方法模式,则可以减少Command子类的膨胀问题。
缺点:
    如果有N个命令,Command的子类就会有N个,这个类膨胀的非常大.
 

命令模式的适用场景

在下面的情况下可以考虑使用命令模式:

  1. 系统需要支持命令的撤销(undo)。命令对象可以把状态存储起来,等到客户端需要撤销命令所产生的效果时,可以调用undo方法吧命令所产生的效果撤销掉。命令对象还可以提供redo方法,以供客户端在需要时,再重新实现命令效果。
  2. 系统需要在不同的时间指定请求、将请求排队。一个命令对象和原先的请求发出者可以有不同的生命周期。意思为:原来请求的发出者可能已经不存在了,而命令对象本身可能仍是活动的。这时命令的接受者可以在本地,也可以在网络的另一个地址。命令对象可以串行地传送到接受者上去。
  3. 如果一个系统要将系统中所有的数据消息更新到日志里,以便在系统崩溃时,可以根据日志里读回所有数据的更新命令,重新调用方法来一条一条地执行这些命令,从而恢复系统在崩溃前所做的数据更新。
  4. 系统需要使用命令模式作为“CallBack(回调)”在面向对象系统中的替代。Callback即是先将一个方法注册上,然后再以后调用该方法。
应用:

让我们以上面的军训的例子来实现一个命令模式,在实现之前,可以参考下命令模式的结构图来分析下实现过程。

  军训场景中,具体的命令即是学生跑1000米,这里学生是命令的接收者,教官是命令的请求者,院领导是命令的发出者,即客户端角色。要实现命令模式,则必须需要一个抽象命令角色来声明约定,这里以抽象类来来表示。命令的传达流程是:

  命令的发出者必须知道具体的命令、接受者和传达命令的请求者,对应于程序也就是在客户端角色中需要实例化三个角色的实例对象了。

  命令的请求者负责调用命令对象的方法来保证命令的执行,对应于程序也就是请求者对象需要有命令对象的成员,并在请求者对象的方法内执行命令。

  具体命令就是跑1000米,这自然属于学生的责任,所以是具体命令角色的成员方法,而抽象命令类定义这个命令的抽象接口。

  有了上面的分析之后,具体命令模式的实现代码如下所示:

  // 教官,负责调用命令对象执行请求
public class Invoke
{
public Command _command;
public Invoke(Command command)
{
this._command = command;
}
public void ExecuteCommand()
{
_command.Action();
}
}
// 命令抽象类
public abstract class Command
{
// 命令应该知道接收者是谁,所以有Receiver这个成员变量
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()
{
// 调用接收的方法,因为执行命令的是学生44
_receiver.Run1000Meters();
}
}
// 命令接收者——学生49
public class Receiver
{
public void Run1000Meters()
{
Console.WriteLine("跑1000米");
}
}

命令模式的实现要点在于把某个具体的命令抽象化为具体的命令类,并通过加入命令请求者角色来实现将命令发送者对命令执行者的依赖分割开,在上面军训的例子中,如果不使用命令模式的话,则命令的发送者将对命令接收者是强耦合的关系,实现代码如下:

    // 院领导
class Program
{
static void Main(string[] args)
{
// 初始化Receiver、Invoke和Command63
Receiver r = new Receiver();
Command c = new ConcreteCommand(r);
Invoke i = new Invoke(c);
// 院领导发出命令68
i.ExecuteCommand();
}
}

行为型---命令模式(Command Pattern)的更多相关文章

  1. 设计模式-15命令模式(Command Pattern)

    1.模式动机 在软件设计中,我们经常需要向某些对象发送请求,但是并不知道请求的接收者是谁,也不知道被请求的操作是哪个,我们只需在程序运行时指定具体的请求接收者即可,此时,可以使用命令模式来进行设计,使 ...

  2. 设计模式 - 命令模式(command pattern) 多命令 具体解释

    命令模式(command pattern) 多命令 具体解释 本文地址: http://blog.csdn.net/caroline_wendy 參考命令模式: http://blog.csdn.ne ...

  3. 设计模式 - 命令模式(command pattern) 具体解释

    命令模式(command pattern) 详细解释 本文地址: http://blog.csdn.net/caroline_wendy 命令模式(command pattern) : 将请求封装成对 ...

  4. 设计模式 - 命令模式(command pattern) 宏命令(macro command) 具体解释

    命令模式(command pattern) 宏命令(macro command) 具体解释 本文地址: http://blog.csdn.net/caroline_wendy 參考: 命名模式(撤销) ...

  5. 乐在其中设计模式(C#) - 命令模式(Command Pattern)

    原文:乐在其中设计模式(C#) - 命令模式(Command Pattern) [索引页][源码下载] 乐在其中设计模式(C#) - 命令模式(Command Pattern) 作者:webabcd ...

  6. 设计模式 - 命令模式(command pattern) 撤销(undo) 具体解释

    命令模式(command pattern) 撤销(undo) 详细解释 本文地址: http://blog.csdn.net/caroline_wendy 參考命令模式: http://blog.cs ...

  7. 二十四种设计模式:命令模式(Command Pattern)

    命令模式(Command Pattern) 介绍将一个请求封装为一个对象,从而使你可用不同的请求对客户进行参数化:对请求排队或记录请求日志,以及支持可取消的操作. 示例有一个Message实体类,某个 ...

  8. 设计模式----行为型模式之命令模式(Command Pattern)

    下面来自head first设计模式的命令模式一章节. 定义 将"请求"封装成对象,以便使用不同的请求.队列或者日志来参数化其他对象.命令模式也支持可撤销的操作. 类图 注: 1. ...

  9. 【UE4 设计模式】命令模式 Command Pattern

    概述 描述 将一个请求封装为一个对象,从而使我们可用不同的请求对客户进行参数化:对请求排队或者记录请求日志,以及支持可撤销的操作. 命令模式是一种对象行为型模式,其别名为动作(Action)模式或事务 ...

  10. 设计模式(六):控制台中的“命令模式”(Command Pattern)

    今天的博客中就来系统的整理一下“命令模式”.说到命令模式,我就想起了控制台(Console)中的命令.无论是Windows操作系统(cmd.exe)还是Linux操作系统(命令行式shell(Comm ...

随机推荐

  1. fiddler中断request,修改参数问题

    fiddler正在学习阶段,遇到了一个问题,就是bpu url后,不会修改参数,今天实验了几次,总算成功了 下面写一下步骤: 1.先打开fiddler 2.打开网站,如百度,在文本框输入1,记住!不要 ...

  2. poj1164 The Castle

    有一个n*m的城堡,由一个个小房间组成,每个房间由一个零和四面的墙组成,每个房间都有一个价值, 价值的计算方式是:west_walls价值为1,north_walls价值为2,east_walls价值 ...

  3. js读取txt文件

    $('#selectAreaFile').on('change',function(e){//用户区域的文件选择        var files=e.target.files;        if ...

  4. 6 week work 2

    CSS颜色表示法和颜色表(调色板) 1.用颜色名表示 如:white.red.greenyellow.gold等. 2.用十六进制的颜色值表示(红.绿.蓝) #FF0000或者#F00 3.用rgb( ...

  5. Android逆向之smali学习

    Smali是Android虚拟机Dalvik反汇编的结果. Dalvik指令集 指令格式为:[op]-[type](可选)/[位宽,默认4位] [目标寄存器],[源寄存器](可选) 赋值:move*  ...

  6. jquery.ocupload上传文件到指定目录

    首先引入两个js <script type="text/javascript" src="${pageContext.request.contextPath }/r ...

  7. eclipse 工作区空格和回车键显示为乱码

    eclipse 工作区空格和回车键显示为乱码 解决方法:Windows => Preferences => General =>Editors =>Text Editor =& ...

  8. Android-获取Html元素

    第一步导包: implementation 'org.jsoup:jsoup:1.10.3' 第二步:需获取解析的Html: <p> <myfont style="colo ...

  9. VSCode插件开发全攻略(五)跳转到定义、自动补全、悬停提示

    更多文章请戳VSCode插件开发全攻略系列目录导航. 跳转到定义 跳转到定义其实很简单,通过vscode.languages.registerDefinitionProvider注册一个provide ...

  10. 目标检测算法(1)目标检测中的问题描述和R-CNN算法

    目标检测(object detection)是计算机视觉中非常具有挑战性的一项工作,一方面它是其他很多后续视觉任务的基础,另一方面目标检测不仅需要预测区域,还要进行分类,因此问题更加复杂.最近的5年使 ...