索引

别名

  • Action
  • Transaction

意图

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

Encapsulate a request as an object, thereby letting you parameterize clients with different requests, queue or log requests, and support undoable operations.

结构

参与者

Command

  • 声明 Execute 操作的接口。

ConcreteCommand

  • 将一个接收者对象绑定于一个动作。
  • 调用接收者相应的操作,以实现 Execute。

Client

  • 创建一个具体 Command 对象并设定它的接收者。

Invoker

  • 要求 Command 执行请求。

Receiver

  • 知道如何实施与执行一个请求相关的操作。任何类都可能作为一个接收者。

适用性

在以下情况下可以使用 Command 模式:

  • Command 模式是回调(callback)机制的一个面向对象的替代品。所谓回调函数是指函数先在某处注册,而它将在稍后某个需要的时候被调用。
  • 在不同的时刻指定、排列和执行请求。Command 对象可以有一个与初始请求无关的生存期。
  • 支持取消操作。需要定义 Unexecute 操作来取消 Execute 操作调用的效果。
  • 支持修改日志,这样当系统崩溃时,这些修改可以被重做一遍。
  • 用构建在原语操作上的高层操作构造一个系统。例如构建事务(Transaction)系统。

效果

  • Command 模式将调用操作的对象与知道如何实现该操作的对象解耦。
  • Command 是 first-class 对象。它们可像其他的对象一样被操纵和扩展。
  • 可以将多个 Command 装配成一个复合 Command。
  • 增加新的 Command 很容易,因为无需改变已有的类

相关模式

  • Composite 模式可被用来实现 MacroCommand。
  • Memento 模式可用来保持某个状态,Command 用这一状态来取消它的效果。
  • 可以使用 Prototype 来拷贝 Command 对象。

实现

实现方式(一):直接注入 Receiver 对象,Command 决定调用哪个方法。

 namespace CommandPattern.Implementation1
{
public abstract class Command
{
public abstract void Execute();
} public class ConcreteCommand : Command
{
private Receiver _receiver; public ConcreteCommand(Receiver receiver)
{
_receiver = receiver;
} public override void Execute()
{
_receiver.Action();
}
} public class Receiver
{
public void Action()
{
// do something
}
} public class Invoker
{
private Command _cmd; public void StoreCommand(Command cmd)
{
_cmd = cmd;
} public void Invoke()
{
if (_cmd != null)
{
_cmd.Execute();
}
}
} public class Client
{
public void TestCase1()
{
Receiver receiver = new Receiver();
Command cmd = new ConcreteCommand(receiver); Invoker invoker = new Invoker();
invoker.StoreCommand(cmd); invoker.Invoke();
}
}
}

实现方式(二):注入 Receiver 的指定方法,Command 仅能调用该方法。

 namespace CommandPattern.Implementation2
{
public abstract class Command
{
public abstract void Execute();
} public class ConcreteCommand : Command
{
private Action _action; public ConcreteCommand(Action action)
{
_action = action;
} public override void Execute()
{
_action.Invoke();
}
} public class Receiver
{
public void Action()
{
// do something
}
} public class Invoker
{
private Command _cmd; public void StoreCommand(Command cmd)
{
_cmd = cmd;
} public void Invoke()
{
if (_cmd != null)
{
_cmd.Execute();
}
}
} public class Client
{
public void TestCase2()
{
Receiver receiver = new Receiver();
Command cmd = new ConcreteCommand(receiver.Action); Invoker invoker = new Invoker();
invoker.StoreCommand(cmd); invoker.Invoke();
}
}
}

实现方式(三):参数化 Command 构造。

 namespace CommandPattern.Implementation3
{
public abstract class Command
{
public abstract void Execute();
} public class ConcreteCommand : Command
{
private Action<string> _action;
private string _state; public ConcreteCommand(Action<string> action, string state)
{
_action = action;
_state = state;
} public override void Execute()
{
_action.Invoke(_state);
}
} public class Receiver
{
public void Action(string state)
{
// do something
}
} public class Invoker
{
private Command _cmd; public void StoreCommand(Command cmd)
{
_cmd = cmd;
} public void Invoke()
{
if (_cmd != null)
{
_cmd.Execute();
}
}
} public class Client
{
public void TestCase3()
{
Receiver receiver = new Receiver();
Command cmd = new ConcreteCommand(receiver.Action, "Hello World"); Invoker invoker = new Invoker();
invoker.StoreCommand(cmd); invoker.Invoke();
}
}
}

实现方式(四):使用泛型减少 Command 子类。

 namespace CommandPattern.Implementation4
{
public abstract class Command
{
public abstract void Execute();
} public class ConcreteCommand<T, S> : Command
{
private Action<T, S> _action;
private T _state1;
private S _state2; public ConcreteCommand(Action<T, S> action, T state1, S state2)
{
_action = action;
_state1 = state1;
_state2 = state2;
} public override void Execute()
{
_action.Invoke(_state1, _state2);
}
} public class Receiver
{
public void Action(string state1, int state2)
{
// do something
}
} public class Invoker
{
private Command _cmd; public void StoreCommand(Command cmd)
{
_cmd = cmd;
} public void Invoke()
{
if (_cmd != null)
{
_cmd.Execute();
}
}
} public class Client
{
public void TestCase4()
{
Receiver receiver = new Receiver();
Command cmd = new ConcreteCommand<string, int>(
receiver.Action, "Hello World", ); Invoker invoker = new Invoker();
invoker.StoreCommand(cmd); invoker.Invoke();
}
}
}

实现方式(五):使用弱引用代替对 Receiver 的强引用。

 namespace CommandPattern.Implementation5
{
public class WeakAction
{
public WeakAction(Action action)
{
Method = action.Method;
Reference = new WeakReference(action.Target);
} protected MethodInfo Method { get; private set; }
protected WeakReference Reference { get; private set; } public bool IsAlive
{
get { return Reference.IsAlive; }
} public object Target
{
get { return Reference.Target; }
} public void Invoke()
{
if (Method != null && IsAlive)
{
Method.Invoke(Target, null);
}
}
} public abstract class Command
{
public abstract void Execute();
} public class ConcreteCommand : Command
{
private WeakAction _action; public ConcreteCommand(Action action)
{
_action = new WeakAction(action);
} public override void Execute()
{
_action.Invoke();
}
} public class Receiver
{
public void Action()
{
// do something
}
} public class Invoker
{
private Command _cmd; public void StoreCommand(Command cmd)
{
_cmd = cmd;
} public void Invoke()
{
if (_cmd != null)
{
_cmd.Execute();
}
}
} public class Client
{
public void TestCase5()
{
Receiver receiver = new Receiver();
Command cmd = new ConcreteCommand(receiver.Action); Invoker invoker = new Invoker();
invoker.StoreCommand(cmd); invoker.Invoke();
}
}
}

实现方式(六):使 Command 支持 Undo 和 Redo。

如果 Command 提供方法逆转操作,例如 Undo 操作,就可以取消执行的效果。为达到这个目的,ConcreteCommand 类可能需要存储额外的状态信息。

这个状态包括:

接收者对象,它真正执行处理该请求的各操作。

接收者上执行操作的参数。

如果处理请求的操作会改变接收者对象中的某些值,那么这些值也必须先存储起来。接收者还必须提供一些操作,以使该命令可将接收者恢复到它先前的状态。

 namespace CommandPattern.Implementation6
{
public abstract class Command
{
public abstract void Execute();
public abstract void Unexecute();
public abstract void Reexecute();
} public class ConcreteCommand : Command
{
private Receiver _receiver;
private string _state;
private string _lastState; public ConcreteCommand(Receiver receiver, string state)
{
_receiver = receiver;
_state = state;
} public override void Execute()
{
_lastState = _receiver.Name;
_receiver.ChangeName(_state);
} public override void Unexecute()
{
_receiver.ChangeName(_lastState);
_lastState = string.Empty;
} public override void Reexecute()
{
Unexecute();
Execute();
}
} public class Receiver
{
public string Name { get; private set; } public void ChangeName(string name)
{
// do something
Name = name;
}
} public class Invoker
{
private Command _cmd; public void StoreCommand(Command cmd)
{
_cmd = cmd;
} public void Invoke()
{
if (_cmd != null)
{
_cmd.Execute();
}
} public void UndoInvoke()
{
if (_cmd != null)
{
_cmd.Unexecute();
}
}
} public class Client
{
public void TestCase6()
{
Receiver receiver = new Receiver();
Command cmd = new ConcreteCommand(receiver, "Hello World"); Invoker invoker = new Invoker();
invoker.StoreCommand(cmd); invoker.Invoke();
invoker.UndoInvoke();
}
}
}

实现方式(七):使 MacroCommand 来管理 Command 序列。

MacroCommand 需要提供增加和删除子 Command 的操作。

 namespace CommandPattern.Implementation7
{
public abstract class Command
{
public abstract void Execute();
} public class MacroCommand : Command
{
private List<Command> _cmdList = new List<Command>(); public MacroCommand()
{
} public void Add(Command cmd)
{
_cmdList.Add(cmd);
} public void Remove(Command cmd)
{
_cmdList.Remove(cmd);
} public override void Execute()
{
foreach (var cmd in _cmdList)
{
cmd.Execute();
}
}
} public class ConcreteCommand1 : Command
{
private Receiver _receiver; public ConcreteCommand1(Receiver receiver)
{
_receiver = receiver;
} public override void Execute()
{
_receiver.Action1();
}
} public class ConcreteCommand2 : Command
{
private Receiver _receiver; public ConcreteCommand2(Receiver receiver)
{
_receiver = receiver;
} public override void Execute()
{
_receiver.Action2();
}
} public class Receiver
{
public void Action1()
{
// do something
} public void Action2()
{
// do something
}
} public class Invoker
{
private Command _cmd; public void StoreCommand(Command cmd)
{
_cmd = cmd;
} public void Invoke()
{
if (_cmd != null)
{
_cmd.Execute();
}
}
} public class Client
{
public void TestCase7()
{
Receiver receiver = new Receiver();
Command cmd1 = new ConcreteCommand1(receiver);
Command cmd2 = new ConcreteCommand2(receiver);
MacroCommand macro = new MacroCommand();
macro.Add(cmd1);
macro.Add(cmd2); Invoker invoker = new Invoker();
invoker.StoreCommand(macro); invoker.Invoke();
}
}
}

设计模式之美》为 Dennis Gao 发布于博客园的系列文章,任何未经作者本人同意的人为或爬虫转载均为耍流氓。

设计模式之美:Command(命令)的更多相关文章

  1. 设计模式14:Command 命令模式(行为型模式)

    Command 命令模式(行为型模式) 耦合与变化 耦合是软件不能抵御变化的根本性原因.不仅实体对象与实体对象之间存在耦合关系,实体对象与行为操作之间也存在耦合关系. 动机(Motivation) 在 ...

  2. C#设计模式之十五命令模式(Command Pattern)【行为型】

    一.引言   今天我们开始讲"行为型"设计模式的第二个模式,该模式是[命令模式],又称为行动(Action)模式或交易(Transaction)模式,英文名称是:Command P ...

  3. C#设计模式之十四命令模式(Command Pattern)【行为型】

    一.引言 今天我们开始讲“行为型”设计模式的第二个模式,该模式是[命令模式],又称为行动(Action)模式或交易(Transaction)模式,英文名称是:Command Pattern.还是老套路 ...

  4. Java设计模式(22)命令模式(Command模式)

    Command模式是最让我疑惑的一个模式,我在阅读了很多代码后,才感觉隐约掌握其大概原理,我认为理解设计模式最主要是掌握起原理构造,这样才对自己实际编程有指导作用.Command模式实际上不是个很具体 ...

  5. C++设计模式-Command命令模式

    Command命令模式作用:将一个请求封装为一个对象,从而使你可用不同的请求对客户进行参数化:对请求排队或记录请求日志,以及支持可撤销的操作. 由于“行为请求者”与“行为实现者”的紧耦合,使用命令模式 ...

  6. 设计模式(十四):Command命令模式 -- 行为型模式

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

  7. 设计模式之美:Memento(备忘录)

    索引 意图 结构 参与者 适用性 效果 相关模式 实现 实现方式(一):Memento 模式结构样式代码. 别名 Token 意图 在不破坏封装性的前提下,捕获一个对象的内部状态,并在该对象之外保存这 ...

  8. 设计模式之美:Interpreter(解释器)

    索引 意图 结构 参与者 适用性 效果 相关模式 实现 实现方式(一):Interpreter 模式结构样式代码. 实现方式(二):解释波兰表达式(Polish Notation). 意图 给定一个语 ...

  9. 设计模式之美:Composite(组合)

    索引 意图 结构 参与者 适用性 缺点 效果 相关模式 实现 实现方式(一):在 Component 中定义公共接口以保持透明性但损失安全性. 意图 将对象组合成树形结构以表示 “部分-整体” 的层次 ...

随机推荐

  1. delphi软件启动的顺序解密。

    运行顺序 1.主窗体的oncreate -- onshow ---- onActivate ---- onResize --- 然后继续走,这个时候主窗体已经显示出来了,猜想delphi的思路是先让主 ...

  2. mysql之预处理语句prepare、execute、deallocate

    预制语句的SQL语法基于三个SQL语句: PREPARE stmt_name FROM preparable_stmt; EXECUTE stmt_name [USING @var_name [, @ ...

  3. SHELL脚本攻略(学习笔记)--2.4 find

    转载请注明出处:http://www.cnblogs.com/f-ck-need-u/p/5916657.html   超级强大的find命令. find搜索是从磁盘搜索,而不是从数据库搜索. 2.4 ...

  4. Java值传递和引用传递详细解说

    前天在做系统的时候被Java中参数传递问题卡了一下,回头查阅了相关的资料,对参数传递问题有了新的了解和掌握,但是有个问题感觉还是很模糊,就是 Java中到底是否只存在值传递,因为在查阅资料时,经常看到 ...

  5. 在Linux下安装配置phpMyAdmin步骤

    本文于CentOS 6.5下测试可行,欢迎转载和指正. phpMyAdmin是一种基于Web的免费MySQL管理工具.phpMyAdmin是用PHP编写的,因此只有支持PHP的服务器才能使用phpMy ...

  6. redis 内存泄露

    http://www.oschina.net/question/2266476_246221 http://stackoverflow.com/questions/24304212/how-to-de ...

  7. CardView的简单介绍

    CardView是Android5.0中的一个全新控件,本质上而言,CardView是一个增加了圆角和阴影效果的FrameLayout,没错它就是一个FrameLayout,一个布局.CardView ...

  8. 插件兼容CommonJS, AMD, CMD 和 原生 JS

    模块标准 CommonJS CommonJS 有三个全局变量 module.exports 和 require.但是由于 AMD 也有 require 这个全局变量,故不使用这个变量来进行检测. 如果 ...

  9. [Linux]CentOS下安装和使用tmux

    前天随意点开博客园,看到了一篇关于tmux的文章 Tmux - Linux从业者必备利器,特意还点进去看了.毕竟Linux对于做游戏服务端开发的我来说,太熟悉不过了.不过我就粗略地看了一眼,就关掉了. ...

  10. rocksdb编译测试的正确姿势

    需要先安装 gflags 在进行 make db_bench 不然运行 db_bench 会出现 Please install gflags to run rocksdb tools 错误 bench ...