一般执行一个操作的过程, 创建对象, 并调用对象的函数, 函数执行, 返回

比如下面的类图, client直接调用Receiver.action

而命令模式, 抽象出command对象, 并在command对象封装对Receiver.action的调用

而client只负责创建command对象(invocation), 并提交给Invoker(通过setCommand), 而command真正的执行(execution)由Invoker控制

从而实现invocation和invoker的分离和解耦合

当然会问, 直接调用那么简单, 为什么要绕那么大的圈来用command?

a. 简化调用过程, 整个调用过程比较繁杂或调用前后需要进行某些额外处理,比如日志,缓存,记录历史操作等

b. 作为"CallBack"在面向对象系统中的替代

c. 支持undo, redo

d. 更关键的是, 命令模式往往会用于异步或并发处理模式

   比如, producer和consumer模式, producer可以不断产生command放到queue里面, 然后可以通过consumer来异步的执行, 达到并发和异步

 

 

命令模式 (Command), 将一个请求封装为一个对象,从而使你可用不同的请求对客户进行参数化;对请求排队或记录请求日志,以及支持可撤销的操作。
这个模式的基本思路是解耦合和责任单一, “行为请求者”与“行为实现者”通常呈现一种“紧耦合”。但在某些场合,比如要对行为进行“记录、撤销/重做、事务”等处理,这种无法抵御变化的紧耦合是不合适的, 所以要使用命令模式来解耦合.

场景, 这个模式在平时用的很多, 编辑器里面很常用的'undo/redo', 就是用的这种模式.
经常举的例子就是点菜, 客人可以直接对厨师进行点菜, 这样做有两点不好
1. 客户和厨师紧耦合, 比如厨师换了, 或菜名换了等等, 客户代码需要跟着改变.
2. 厨师除了要烹饪外, 还需要记录每个客户请求, 当客户比较多时, 且客户请求是会变化的, 换个菜, 退个菜, 这个厨师就忙不过来了, 很容易记错. 这就违反了单一责任原则, 厨师就应该负责烹饪, 其他的事应该有专门的waiter负责.
这就是命令模式, 当你需要对请求者的请求(函数调用)进行记录, undo, redo等操作时, 需要单独抽象出Invoker类来处理, 而不要直接耦合在Receiver中.
上面的例子中, 客户是Client, 服务生是Invoker, 厨师是Receiver, 客户请求是Command

class Receiver //最终命令的执行者, 厨师
{
public void Action()
{
//具体的命令执行, 烹饪菜肴
}
} class ConcreteCommand : Command //具体的客户请求, 点一道菜
{
protected Receiver rec; //该情况的执行者, 这道菜哪个厨师烧
public Command(Receiver rec)
{
this.rec = rec;
} public void Execute()
{
rec.Action()//让执行者执行命令
}
} class Invoker //Command模式的核心, 客户请求的管理者, 服务生waiter
{
private List<Command> cmds = new List<Command>(); //用于保存客户请求 public void SetOrder(Command cmd)
{
if Valid(cmd) //需要判断请求是否合理, 比如是否有这道菜
{
cmds.Add(cmd); //增加请求
}
} public void CancelOrder(Command cmd)
{
cmds.Remove(cmd); //删除请求
} public void Execute() //执行所有请求
{
for cmd in cmds
{
cmd.Excute();
}
}
}
public class Client {
public void client(){
//创建接收者
Receiver receiver = new Receiver();
//创建命令对象,设定它的接收者
Command command = new ConcreteCommand(receiver);
//创建Invoker,把命令对象设置进去
Invoker invoker = new Invoker();
invoker.SetOrder(command);
}
}

Invoker具体的实现可能变化多端, 但是本质就是通过Invoke来把客户请求抽象成command, 并且保存和管理commands, 向用户提供如do, redo, undo, rollback等操作, 而这些操作对receiver都是透明的, 这取决于客户和receiver的解耦. 

Design Pattern - 命令模式的更多相关文章

  1. Thinking In Design Pattern——MVP模式演绎

    原文<Thinking In Design Pattern——MVP模式演绎>不知为何丢失了,故重新整理了一遍. 目录 What Is MVP Domain Model StubRepos ...

  2. [Design Pattern] Command Pattern 命令模式

    发现公司的代码好像有用到 Command Pattern,回顾重温下. Command Pattern 的类图结构如下: 参考 <Head First Design Patterns(英文版)& ...

  3. Command Pattern 命令模式

    定义: 命令模式将‘请求’封装成对象,以便使用不同的请求,队列或者日志来参数化其他对象,命令模式也支持可撤销的操作. 类图 如上图所示:Command类是用来声明执行操作的接口:ConcreteCom ...

  4. Command Pattern -- 命令模式原理及实现(C++)

    主要参考<大话设计模式>和<设计模式:可复用面向对象软件的基础>两本书.本文介绍命令模式的实现. What it is:Encapsulate a request as an ...

  5. (Command Pattern)命令模式

    定义 将“请求”封装成对象,以便使用不同的请求.队列或者日志来参数化其他对象.命令模式也支持可撤销的操作. 结构图: 命令模式的角色划分: Reciever(命令的接收者):接收命令,并知道如何进行必 ...

  6. Design Pattern - 访问者模式

    访问者模式 访问者模式(Visitor), 表示一个作用于某对象结构中的各元素的操作.它使你可以在不改变各元素的类的前提下定义作用于这些元素的新操作. 这个模式相对比较复杂, 而又很少能被用上, 拿G ...

  7. 使用PHP实现命令模式(转)

    <?php /** * 命令模式 2010-08-21 sz * @author phppan.p#gmail.com http://www.phppan.com * 哥学社成员(http:// ...

  8. Command and Query Responsibility Segregation (CQRS) Pattern 命令和查询职责分离(CQRS)模式

    Segregate operations that read data from operations that update data by using separate interfaces. T ...

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

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

随机推荐

  1. 优化数据页面(22)——n:n的数据关系

    设计要点:优化数据页面.界面设计.美化exce 阿金:那n::n就复杂了,你倒是想留有空间. 可是现实社会有时却不同意. 秀秀:唉.说的也是. 阿金:那怎么表达才合适啊? 秀秀:仅仅实用网格了. 阿金 ...

  2. debian下运行netstat失败

    如果提示:bash: netstat: command not found 说明没有安装netstat工具,而该工具在 net-tools 工具包内. apt-get install net-tool ...

  3. 多线程-AbstractQueuedSynchronizer(AQS)

    概述 从使用者的角度,AQS的功能可分为两类:独占功能和共享功能.它的子类中,要么实现并使用了它独占功能的API,要么使用了共享锁的功能,而不会同时使用两套API,即使是它的子类ReentrantRe ...

  4. hdu 4771 Stealing Harry Potter's Precious (2013亚洲区杭州现场赛)(搜索 bfs + dfs) 带权值的路径

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4771 题目意思:'@'  表示的是起点,'#' 表示的是障碍物不能通过,'.'  表示的是路能通过的: ...

  5. 字符串操作:int 转 string

    strstream ss; string ch; ss<<i; ss>>ch;

  6. treeMap,key排序,value排序

    HashMap与TreeMap按照key和value排序 使用一个场景是mapreduce中用解决topn问题是用value 排序 topn MapReducetopN

  7. PHP从千千静听服务器获取lrc歌词

    <?php //转载请注明出处 uenucom function SingleDecToHex($dec)  {  $tmp="";  $dec=$dec%16;  if($ ...

  8. EMQ进行HttpApi登录问题

    今天进行EMQ http api调用的时候遇到一个问题,一直弹出登录验证框 在官网资料中也找不到相关的接口,如下图: 以前也经常看到这种登录,不过我这里没有用程序去调用过这样类似的接口. 后来我想到经 ...

  9. eclispe luna 安装subversive和svn connector插件

    1. subversive安装 下载地址: http://www.eclipse.org/subversive/latest-releases.php 或者在eclipse luna的marketpl ...

  10. Nginx中修改php.ini的上传设置upload_max_filesize的值

    普遍的网络越来越快,以前小家子气的2M上传限制慢慢变得不合时宜了.最近就把2M的限制直接提升到了20M...代码层面很快就修改好了,没什么可说的.但是上线的话还得修改一下服务器的配置.服务器是Ngin ...