Estaba buscando una implementación del patrón Command en Python ... (De acuerdo con Wikipedia,

El patrón de comando es un patrón de diseño en el que un objeto se utiliza para representar y encapsular toda la información necesaria para llamar a un método más adelante.

)

Lo único que encontré fue Command Dispatch 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()

Puede que me equivoque, pero parece que estos son dos conceptos diferentes, que accidentalmente tienen nombres similares.

¿Me estoy perdiendo de algo?

24
legesh 29 sep. 2009 a las 23:23

4 respuestas

La mejor respuesta

El patrón de comando más simple ya está integrado en Python, simplemente use un invocable:

def greet(who):
    print "Hello %s" % who

greet_command = lambda: greet("World")
# pass the callable around, and invoke it later
greet_command()

El patrón de comando como un patrón de diseño orientado a objetos tiene más sentido si sus comandos necesitan poder hacer más que simplemente ser invocados. El caso de uso común es cuando necesita poder deshacer / rehacer sus acciones. Entonces, una clase de comando es una buena manera de acoplar las acciones hacia adelante y hacia atrás juntas. Por ejemplo:

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
58
martineau 15 sep. 2013 a las 10:41

Si recuerdo correctamente la pandilla de cuatro, el patrón de Comando se trata de comandos como "Archivo - Guardar", no comandos como "svn commit", que es para lo que sirve su código.

Martin sugiere que el patrón Command no es necesario porque las funciones como objetos de primera clase toman su lugar, pero el patrón Command es más rico que solo doit(), teniendo, por ejemplo, también undo(), is_enabled(), etc. .

4
Ned Batchelder 29 sep. 2009 a las 19:39

Hice algunas búsquedas y encontré esto. Parece hacer el trabajo de encapsular una acción.

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
FModa3 29 sep. 2009 a las 19:36

Sí, se pierde algo: el patrón de comando solo es necesario en lenguajes que no tienen punteros de función (o funciones como objetos de primera clase), como Java. En lenguajes con funciones como objetos, puede usar la función misma; no es necesario tener un objeto de comando separado (que luego debería tener un método "doit").

En el ejemplo podría citar, la llamada getattr() le da el "objeto de comando" (es decir, el método enlazado); agregando paréntesis después de que "invoca" (es decir, llama) al objeto de comando.

4
Martin v. Löwis 29 sep. 2009 a las 19:26