Python 中的通用命令模式和命令调度模式
Posted
技术标签:
【中文标题】Python 中的通用命令模式和命令调度模式【英文标题】:General Command pattern and Command Dispatch pattern in Python 【发布时间】: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()
可能是我错了,但看起来这是两个不同的概念,意外地有相似的名称。
我错过了什么吗?
【问题讨论】:
【参考方案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)
【讨论】:
apply
被认为是“非必要的”:docs.python.org/2/library/…【参考方案4】:
如果我没记错的话,命令模式是关于像“文件 - 保存”这样的命令,而不是像“svn commit”这样的命令,这是你的代码的优点。
Martin 建议不需要 Command 模式,因为作为一等对象的函数取而代之,但 Command 模式比 doit()
更丰富,例如还有 undo()
、is_enabled()
等。
【讨论】:
我相信 undo 的集成是令人困惑的问题。我看过的命令模式的每个描述都提到您可以撤消,但实际代码只有一个 Execute() 方法的接口(不支持撤消)。所以我认为命令模式的感知“丰富性”实际上混合了独立的用例,其中主要用例只是关于无参数回调操作。以上是关于Python 中的通用命令模式和命令调度模式的主要内容,如果未能解决你的问题,请参考以下文章