2009-09-29 20 views
22

Yo estaba buscando un Comando aplicación patrón en Python ... (Según Wikipedia,patrón Comando General y el patrón de despacho de comandos en Python

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 en un momento posterior.

)

El único que encontré fue la orden de Despacho 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 ser que me equivoque, pero parece que se trata de dos conceptos diferentes, que accidentalmente tienen nombres similares.

¿Echo de falta algo?

Respuesta

54

El comando más simple patrón ya está integrado en Python, basta con utilizar un exigible:

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 comandos como un patrón de diseño orientado a objetos tiene más sentido si los comandos tienen que ser capaces de hacer algo más que invocar. El uso común es cuando necesitas poder deshacer/rehacer tus acciones. Entonces, una clase de comando es una buena forma de combinar las acciones hacia delante y hacia atrás. 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 
+0

Gracias por su ejemplo de deshacer: es pequeño (tan fácil de entender) e ilustra muy bien el concepto. –

+0

+1 Ejemplo claro y simple. – hiwaylon

2

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

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

+8

Creo que es una mala idea presumir que el patrón de comando no es "necesario" solo porque una función es un objeto de primera clase. El patrón de comando no se trata solo de pasar por callables, se trata de crear descripciones sólidas de los modelos de ejecución. También suele ser útil poder persistir un comando parcialmente aplicado durante un período de tiempo, luego recuperar ese comando y completarlo más tarde. Las funciones persistentes en python son complicadas, persistiendo un comando definido por el usuario es menor. – apiguy

3

Hizo algunas búsquedas y encontré esto. Parece que hace 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) 
+0

'apply' se considera" no esencial ": https://docs.python.org/2/library/functions.html # non-essential-built-in-funcs – Florian

2

Si no recuerdo mal la banda de los cuatro, el patrón de comando se trata de comandos como "Archivo - Guardar", no comandos como "svn commit", que es lo que su código es bueno para.

Martin sugiere el patrón Command es innecesario ya que las funciones como objetos de primera clase tienen su lugar, pero el patrón de comandos es más rica que simplemente doit(), que tiene, por ejemplo, también undo(), is_enabled(), etc.

+1

Creo que la integración de deshacer es confusa. Cada descripción del patrón de comando que he examinado menciona que puede deshacer, pero luego el código real solo tiene una interfaz para un método Execute() (sin soporte para Deshacer). Por lo tanto, creo que la "riqueza" percibida del patrón de comando en realidad mezcla casos de uso independientes, donde el caso de uso primario es solo acerca de operaciones de devolución de llamada * sin parámetros *. –

Cuestiones relacionadas