【问题标题】:General Command pattern and Command Dispatch pattern in PythonPython 中的通用命令模式和命令调度模式
【发布时间】:2010-12-02 10:34:22
【问题描述】:

我正在寻找 Python 中的 Command 模式实现... (根据Wikipedia

命令模式是一种设计 对象用于的模式 代表和封装所有 调用方法所需的信息 稍后。

)

我发现的唯一东西是命令调度pattern

class Dispatcher:

    def do_get(self): ...

    def do_put(self): ...

    def error(self): ...

    def dispatch(self, command):
        mname = 'do_' + command
        if hasattr(self, mname):
            method = getattr(self, mname)
            method()
        else:
            self.error()

可能是我错了,但看起来这是两个不同的概念,意外地有相似的名称。

我错过了什么吗?

【问题讨论】:

    标签: python design-patterns oop


    【解决方案1】:

    最简单的命令模式已经内置在 Python 中,只需使用可调用对象:

    def greet(who):
        print "Hello %s" % who
    
    greet_command = lambda: greet("World")
    # pass the callable around, and invoke it later
    greet_command()
    

    如果您的命令需要能够做的不仅仅是被调用,那么作为面向对象设计模式的命令模式会更有意义。常见的用例是当您需要能够撤消/重做您的操作时。那么命令类是将前进和后退动作耦合在一起的好方法。例如:

    class MoveFileCommand(object):
        def __init__(self, src, dest):
            self.src = src
            self.dest = dest
            os.rename(self.src, self.dest)
        def undo(self):
            os.rename(self.dest, self.src)
    
    undo_stack = []
    undo_stack.append(MoveFileCommand('foo.txt', 'bar.txt'))
    undo_stack.append(MoveFileCommand('bar.txt', 'baz.txt'))
    # foo.txt is now renamed to baz.txt
    undo_stack.pop().undo() # Now it's bar.txt
    undo_stack.pop().undo() # and back to foo.txt
    

    【讨论】:

    • 感谢您的撤消示例:它很小(很容易理解)并且很好地说明了这个概念。
    【解决方案2】:

    是的,您确实错过了一些东西:命令模式仅在没有函数指针(或作为第一类对象的函数)的语言中是必需的,例如 Java。在具有函数即对象的语言中,您可以使用函数本身;不需要有一个单独的命令对象(它应该有一个“doit”方法)。

    在您能否引用的示例中,getattr() 调用为您提供“命令对象”(即绑定方法);在它“调用”(即调用)命令对象之后添加括号。

    【讨论】:

    • 我认为仅仅因为函数是第一类对象就假定命令模式不是“必要的”是一个坏主意。命令模式不仅仅是传递可调用对象,它是关于创建执行模型的健壮描述。能够将部分应用的命令保留一段时间,然后调用该命令并稍后完成它通常也很有用。在 python 中持久化函数很棘手,持久化用户定义的命令就不那么简单了。
    【解决方案3】:

    做了一些搜索并找到了这个。它似乎完成了封装动作的工作。

    def demo(a,b,c):
        print 'a:',a
        print 'b:',b
        print 'c:',c
    
    class Command:
        def __init__(self, cmd, *args):
            self._cmd=cmd
            self._args=args
    
        def __call__(self, *args):
           return apply(self._cmd, self._args+args)
    
    
    cmd=Command(dir,__builtins__)
    print cmd()
    
    cmd=Command(demo,1,2)
    cmd(3)
    

    【讨论】:

    【解决方案4】:

    如果我没记错的话,命令模式是关于像“文件 - 保存”这样的命令,而不是像“svn commit”这样的命令,这是你的代码的优点。

    Martin 建议不需要 Command 模式,因为作为一等对象的函数取而代之,但 Command 模式比 doit() 更丰富,例如还有 undo()is_enabled() 等。

    【讨论】:

    • 我相信 undo 的集成是令人困惑的问题。我看过的命令模式的每个描述都提到您可以撤消,但实际代码只有一个 Execute() 方法的接口(不支持撤消)。所以我认为命令模式的感知“丰富性”实际上混合了独立的用例,其中主要用例只是关于无参数回调操作。
    猜你喜欢
    • 2016-07-31
    • 2012-10-24
    • 2011-03-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-04-22
    相关资源
    最近更新 更多