Design Pattern - 命令模式

简介:

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

比如下面的类图, 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

image_thumb[1]

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的解耦. 


本文章摘自博客园,原文发布日期:2013-11-19

目录
相关文章
|
设计模式 语音技术
设计模式12 - 命令模式【Command Pattern】
设计模式12 - 命令模式【Command Pattern】
54 0
|
设计模式 数据库
命令模式(Command Pattern)
命令模式(Command Pattern)是一种行为型设计模式,它将请求或操作封装成对象,以便于使用不同的请求、队列或日志来参数化其他对象。命令模式可以将命令的请求者和执行者解耦,从而增强系统的灵活性和可扩展性。
94 2
|
存储 Java 程序员
行为型模式 - 命令模式(Command Pattern)
行为型模式 - 命令模式(Command Pattern)
|
设计模式 安全 Java
设计模式|从Visitor Pattern说到Pattern Matching
在软件开发领域,我们每次遇到的问题可能都各不相同,有些是跟电商业务相关的,有些是跟底层数据结构相关的,而有些则可能重点在性能优化上。然而不管怎么样,我们在代码层面上解决问题的方法都有一定的共性。有没有人总结过这些共性呢?
设计模式|从Visitor Pattern说到Pattern Matching
|
C# 设计模式 程序员
C#设计模式(15)——命令模式(Command Pattern)
原文:C#设计模式(15)——命令模式(Command Pattern) 一、前言   之前一直在忙于工作上的事情,关于设计模式系列一直没更新,最近项目中发现,对于设计模式的了解是必不可少的,当然对于设计模式的应用那更是重要,可以说是否懂得应用设计模式在项目中是衡量一个程序员的技术水平,因为对于一个功能的实现,高级工程师和初级工程师一样都会实现,但是区别在于它们实现功能的可扩展和可维护性,也就是代码的是否“优美”、可读。
1152 0
|
设计模式 图形学
设计模式---命令模式(DesignPattern_Command)
DesignPattern_Command 摘录自:设计模式与游戏完美开发 十年磨一剑,作者将设计模式理论巧妙地融入到实践中,以一个游戏的完整实现呈现设计模式的应用及经验的传承 《轩辕剑》之父——蔡明宏、资深游戏制作人——李佳泽、Product...
812 0